From af312ffbe3e356a93f8c9db4784a9313693e1a6e Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Mon, 13 Nov 2017 22:12:36 +0000 Subject: [PATCH 001/289] Updated changelog for 0.9.5 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2c0eb1..78d4d66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ # Next Release +# v0.9.5 + +* Added leaderboard api for web-app with pagination * Location is now updated on registration. Customers location is truncated to 2 decimal places based on their postcode. * Location is also updated on changing a users postcode From f0b1540f3edca7d583b7b79e0fe86d522b98350e Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 14 Nov 2017 12:57:28 +0000 Subject: [PATCH 002/289] Refactored csv import flash errors --- lib/Pear/LocalLoop/Controller/Admin/Import.pm | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Import.pm b/lib/Pear/LocalLoop/Controller/Admin/Import.pm index c2b3ef1..c1c2fe1 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Import.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Import.pm @@ -69,7 +69,7 @@ sub post_add { }; if ( defined $error ) { - $c->flash( error => $error, csv_data => $csv_data, date_format => $date_format ); + $c->_csv_flash_error( $error ); $c->redirect_to( '/admin/import/add' ); return; } @@ -78,7 +78,7 @@ sub post_add { my @required = grep {/^user$|^value$|^date$|^organisation$/} @csv_headers; unless ( scalar( @required ) == 4 ) { - $c->flash( error => 'Required columns not available', csv_data => $csv_data, date_format => $date_format ); + $c->_csv_flash_error( 'Required columns not available' ); $c->redirect_to( '/admin/import/add' ); return; } @@ -86,7 +86,7 @@ sub post_add { my $csv_output = $csv->getline_hr_all( $fh ); unless ( scalar( @$csv_output ) ) { - $c->flash( error => "No data found", csv_data => $csv_data, date_format => $date_format ); + $c->_csv_flash_error( "No data found" ); $c->redirect_to( '/admin/import/add' ); return; } @@ -94,7 +94,7 @@ sub post_add { for my $data ( @$csv_output ) { for my $key ( qw/ user value organisation / ) { unless ( defined $data->{$key} ) { - $c->flash( error => "Undefined [$key] data found", csv_data => $csv_data, date_format => $date_format ); + $c->_csv_flash_error( "Undefined [$key] data found" ); $c->redirect_to( '/admin/import/add' ); return; } @@ -103,7 +103,7 @@ sub post_add { my $dtp = DateTime::Format::Strptime->new( pattern => $date_format ); my $dt_obj = $dtp->parse_datetime($data->{date}); unless ( defined $dt_obj ) { - $c->flash( error => "Undefined or incorrect format for [date] data found", csv_data => $csv_data, date_format => $date_format ); + $c->_csv_flash_error( "Undefined or incorrect format for [date] data found" ); $c->redirect_to( '/admin/import/add' ); return; } @@ -126,7 +126,7 @@ sub post_add { ); unless ( defined $value_set ) { - $c->flash( error => 'Error creating new Value Set', csv_data => $csv_data, date_format => $date_format ); + $c->_csv_flash_error( 'Error creating new Value Set' ); $c->redirect_to( '/admin/import/add' ); return; } @@ -135,6 +135,17 @@ sub post_add { $c->redirect_to( '/admin/import/' . $value_set->id ); } +sub _csv_flash_error { + my ( $c, $error ) = @_; + $error //= "An error occurred"; + + $c->flash( + error => $error, + csv_data => $c->param('csv'), + date_format => $c->param('date_format'), + ); +} + sub get_user { my $c = shift; my $set_id = $c->param('set_id'); @@ -182,6 +193,8 @@ sub get_user { ); } + + sub get_org { my $c = shift; From 9d07830e272accfcaf9556c715c09eb6b7d7becd Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 14 Nov 2017 15:02:46 +0000 Subject: [PATCH 003/289] Added org lookup and assignment for import --- lib/Pear/LocalLoop.pm | 1 - lib/Pear/LocalLoop/Controller/Admin/Import.pm | 45 ++++++++++++++++--- templates/admin/import/get_org.html.ep | 36 +++++++++++++++ templates/admin/import/list.html.ep | 6 ++- 4 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 templates/admin/import/get_org.html.ep diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 2980c4e..b8d768b 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -207,7 +207,6 @@ sub startup { $admin_routes->get('/import/:set_id')->to('admin-import#list'); $admin_routes->get('/import/:set_id/user')->to('admin-import#get_user'); $admin_routes->get('/import/:set_id/org')->to('admin-import#get_org'); - $admin_routes->post('/import/:set_id/org')->to('admin-import#set_org'); $admin_routes->get('/import/:set_id/:value_id')->to('admin-import#get_value'); $admin_routes->post('/import/:set_id/:value_id')->to('admin-import#post_value'); diff --git a/lib/Pear/LocalLoop/Controller/Admin/Import.pm b/lib/Pear/LocalLoop/Controller/Admin/Import.pm index c1c2fe1..9d840a1 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Import.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Import.pm @@ -193,16 +193,51 @@ sub get_user { ); } - - sub get_org { my $c = shift; + my $set_id = $c->param('set_id'); + my $org_name = $c->param('org'); -} + my $values_rs = $c->result_set->find($set_id)->values->search( + { + org_name => $org_name, + ignore_value => 0, + } + ); -sub set_org { - my $c = shift; + unless ( $values_rs->count > 0 ) { + $c->flash( error => 'Organisation not found or all values are ignored' ); + return $c->redirect_to( '/admin/import/' . $set_id ); + } + + my $lookup_result = $c->result_set->find($set_id)->lookups->find( + { name => $org_name }, + ); + + my $entity_id = $c->param('entity'); + + my $orgs_rs = $c->schema->resultset('Organisation'); + if ( defined $entity_id && $orgs_rs->find({ entity_id => $entity_id }) ) { + if ( defined $lookup_result ) { + $lookup_result->update({ entity_id => $entity_id }); + } else { + $lookup_result = $c->result_set->find($set_id)->lookups->create( + { + name => $org_name, + entity_id => $entity_id, + }, + ); + } + } elsif ( defined $entity_id ) { + $c->stash( error => "Organisation does not exist" ); + } + + $c->stash( + orgs_rs => $orgs_rs, + lookup => $lookup_result, + org_name => $org_name, + ); } sub get_value { diff --git a/templates/admin/import/get_org.html.ep b/templates/admin/import/get_org.html.ep new file mode 100644 index 0000000..b6bc8a1 --- /dev/null +++ b/templates/admin/import/get_org.html.ep @@ -0,0 +1,36 @@ +% layout 'admin_errors'; +% title 'Import'; +
+
+

<%= $org_name %>

+
+ +
+
+

+ Organisations +

+
+ Choose a user to assign to this name +
+
+ % for my $org ( $orgs_rs->all ) { + +
+
+ %= $org->name +
+
+
+ % } +
+
+
+
+ diff --git a/templates/admin/import/list.html.ep b/templates/admin/import/list.html.ep index 919e982..e7b8bac 100644 --- a/templates/admin/import/list.html.ep +++ b/templates/admin/import/list.html.ep @@ -59,10 +59,14 @@ %= $org->org_name
+ % if ( my $lookup = $import_lookup_rs->find({ name => $org->org_name }) ) { + <%= $lookup->entity->name %> + % } else { Unassigned + % }
From 423c68aca26eae3ed2ab69a0fec62cf3b9363c95 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 14 Nov 2017 18:41:54 +0000 Subject: [PATCH 004/289] Allow for ignoring of values in import and toggle showing of them --- lib/Pear/LocalLoop.pm | 3 +- lib/Pear/LocalLoop/Controller/Admin/Import.pm | 36 ++++++++++++++----- .../LocalLoop/Schema/ResultSet/ImportSet.pm | 9 +++-- templates/admin/import/list.html.ep | 10 +++++- templates/layouts/admin_errors.html.ep | 8 ++--- 5 files changed, 48 insertions(+), 18 deletions(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index b8d768b..7038f70 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -208,8 +208,7 @@ sub startup { $admin_routes->get('/import/:set_id/user')->to('admin-import#get_user'); $admin_routes->get('/import/:set_id/org')->to('admin-import#get_org'); - $admin_routes->get('/import/:set_id/:value_id')->to('admin-import#get_value'); - $admin_routes->post('/import/:set_id/:value_id')->to('admin-import#post_value'); + $admin_routes->get('/import/:set_id/ignore/:value_id')->to('admin-import#ignore_value'); # my $user_routes = $r->under('/')->to('root#under'); # $user_routes->get('/home')->to('root#home'); diff --git a/lib/Pear/LocalLoop/Controller/Admin/Import.pm b/lib/Pear/LocalLoop/Controller/Admin/Import.pm index 9d840a1..8f40971 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Import.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Import.pm @@ -27,10 +27,12 @@ sub list { my $c = shift; my $set_id = $c->param('set_id'); + my $include_ignored = $c->param('ignored'); + my $import_set = $c->result_set->find($set_id); - my $import_value_rs = $c->result_set->get_values($set_id); - my $import_users_rs = $c->result_set->get_users($set_id); - my $import_org_rs = $c->result_set->get_orgs($set_id); + my $import_value_rs = $c->result_set->get_values($set_id, $include_ignored); + my $import_users_rs = $c->result_set->get_users($set_id, $include_ignored); + my $import_org_rs = $c->result_set->get_orgs($set_id, $include_ignored); my $import_lookup_rs = $c->result_set->get_lookups($set_id); $c->stash( @@ -240,14 +242,32 @@ sub get_org { ); } -sub get_value { +sub ignore_value { my $c = shift; my $set_id = $c->param('set_id'); -} + my $value_id = $c->param('value_id'); -sub post_value { - my $c = shift; - my $set_id = $c->param('set_id'); + my $set_result = $c->result_set->find($set_id); + unless ( defined $set_result ) { + $c->flash( error => "Set does not exist" ); + return $c->redirect_to( '/admin/import' ); + } + + my $value_result = $set_result->values->find($value_id); + unless ( defined $value_result ) { + $c->flash( error => "Value does not exist" ); + return $c->redirect_to( '/admin/import/' . $set_id ); + } + + $value_result->update({ ignore_value => $value_result->ignore_value ? 0 : 1 }); + + $c->flash( success => "Updated value" ); + my $referer = $c->req->headers->header('Referer'); + return $c->redirect_to( + defined $referer + ? $c->url_for($referer)->path_query + : '/admin/import/' . $set_id + ); } 1; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm b/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm index b8bd24e..9efad48 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm @@ -8,10 +8,11 @@ use base 'DBIx::Class::ResultSet'; sub get_values { my $self = shift; my $id = shift; + my $include_ignored = shift; return $self->find($id)->search_related( 'values', - undef, + ( $include_ignored ? {} : { ignore_value => 0 } ), { order_by => { '-asc' => 'id' }, }, @@ -21,8 +22,9 @@ sub get_values { sub get_users { my $self = shift; my $id = shift; + my $include_ignored = shift; - return $self->get_values($id)->search({}, + return $self->get_values($id, $include_ignored)->search({}, { group_by => 'user_name', }, @@ -32,8 +34,9 @@ sub get_users { sub get_orgs { my $self = shift; my $id = shift; + my $include_ignored = shift; - return $self->get_values($id)->search({}, + return $self->get_values($id, $include_ignored)->search({}, { group_by => 'org_name', }, diff --git a/templates/admin/import/list.html.ep b/templates/admin/import/list.html.ep index e7b8bac..b1c8045 100644 --- a/templates/admin/import/list.html.ep +++ b/templates/admin/import/list.html.ep @@ -78,6 +78,10 @@

%= format_human_datetime $import_set->date; + + Toggle show Ignored +

Content listed in original order of import @@ -99,7 +103,11 @@ <%= $import_value->org_name %>
- Ignore + % if ( $import_value->ignore_value ) { + Un Ignore + % } else { + Ignore + % }
diff --git a/templates/layouts/admin_errors.html.ep b/templates/layouts/admin_errors.html.ep index 930bdf3..808a5b9 100644 --- a/templates/layouts/admin_errors.html.ep +++ b/templates/layouts/admin_errors.html.ep @@ -60,13 +60,13 @@
- % if ( my $error = flash 'error' ) { + % if ( my $f_error = flash 'error' ) { - % } elsif ( my $error = stash 'error' ) { + % } elsif ( my $s_error = stash 'error' ) { % } elsif ( my $success = flash 'success' ) { % }
-
-
-

- CSV Import - Import Data -

-
+
+

CSV Import

+ Import Data
% for my $import ( $import_rs->all ) { + % my $total = $import_rs->get_values( $import->id, 1, 1 )->count; + % my $unimported = $import_rs->get_values( $import->id, undef, undef )->count; + % my $with_ignored = $import_rs->get_values( $import->id, 1, undef )->count; + % my $with_imported = $import_rs->get_values( $import->id, undef, 1 )->count; + % my $ignored_total = $with_ignored - $unimported; + % my $imported_total = $with_imported - $unimported;
-
+

%= format_human_datetime $import_set->date; - Toggle show Ignored + <%= $c->param('ignored') ? 'Hide' : 'Show' %> Ignored + + + <%= $c->param('imported') ? 'Hide' : 'Show' %> Imported +

Content listed in original order of import
% for my $import_value ( $import_value_rs->all ) { + % my $user_lookup = $import_lookup_rs->{ $import_value->user_name }; + % my $purchase_lookup = parse_currency $import_value->purchase_value; + % my $org_lookup = $import_lookup_rs->{ $import_value->org_name };
<%= $import_value->user_name %> + % if ( defined $user_lookup ) { +
+ <%= $user_lookup->{name} %> + % }
<%= format_human_datetime $import_value->purchase_date %>
<%= $import_value->purchase_value %> +
+ <%= $purchase_lookup %>
<%= $import_value->org_name %> + % if ( defined $org_lookup ) { +
+ <%= $org_lookup->{name} %> + % }
- % if ( $import_value->ignore_value ) { - Un Ignore + % if ( defined $import_value->transaction_id ) { + % } else { - Ignore + % if ( defined $user_lookup && defined $org_lookup && $purchase_lookup ) { + + % } + % if ( $import_value->ignore_value ) { + Un Ignore + % } else { + Ignore + % } % }
@@ -115,4 +140,7 @@
+
From b3036c13ee0242a8f1d8d25fad65791061db551b Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Thu, 16 Nov 2017 15:12:46 +0000 Subject: [PATCH 006/289] Changed non-local-org badge to secondary colour in backend --- templates/admin/organisations/list.html.ep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/admin/organisations/list.html.ep b/templates/admin/organisations/list.html.ep index 0203c5d..f0b53ef 100644 --- a/templates/admin/organisations/list.html.ep +++ b/templates/admin/organisations/list.html.ep @@ -33,7 +33,7 @@ % } elsif ( $org_result->is_local ) { Local Org % } else { - Non Local Org + Non Local Org % }
From 9517b98c247b400b4ffb0af065e4118fe9b65759 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Fri, 17 Nov 2017 18:09:08 +0000 Subject: [PATCH 007/289] Removed unused template --- templates/admin/import/get_value.html.ep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 templates/admin/import/get_value.html.ep diff --git a/templates/admin/import/get_value.html.ep b/templates/admin/import/get_value.html.ep deleted file mode 100644 index e69de29..0000000 From a11727ba1cde8ffecfcbb2d7d367868c8e9333ef Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Fri, 17 Nov 2017 18:09:49 +0000 Subject: [PATCH 008/289] Refactored valid read template slightly and added merge link --- .../admin/organisations/valid_read.html.ep | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/templates/admin/organisations/valid_read.html.ep b/templates/admin/organisations/valid_read.html.ep index db6bd95..046f3f9 100644 --- a/templates/admin/organisations/valid_read.html.ep +++ b/templates/admin/organisations/valid_read.html.ep @@ -41,19 +41,34 @@ function initMap() {
- +
- +
- +
@@ -67,13 +82,21 @@ function initMap() {
- +
- pending ? '' : ' checked' %>> + pending ? '' : ' checked' %>>
@@ -92,6 +115,9 @@ function initMap() {
+
@@ -117,9 +143,9 @@ function initMap() {
From: <%= $transaction->buyer->name %>
To: <%= $transaction->seller->name %>
-
Value: <%= $transaction->value %>
-
Submitted At: <%= $transaction->submitted_at %>
-
Purchase Time: <%= $transaction->purchase_time %>
+
Value: <%= format_currency_from_db $transaction->value %>
+
Submitted At: <%= format_human_datetime $transaction->submitted_at %>
+
Purchase Time: <%= format_human_datetime $transaction->purchase_time %>
% } From baffe144f3865c94532ea2ca9bd1ff2555f68582 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Fri, 17 Nov 2017 18:10:16 +0000 Subject: [PATCH 009/289] Added major merge code for merging organisations --- lib/Pear/LocalLoop.pm | 3 + .../Controller/Admin/Organisations.pm | 105 ++++++++++++++++++ lib/Pear/LocalLoop/Plugin/Currency.pm | 5 + .../admin/organisations/merge_detail.html.ep | 81 ++++++++++++++ .../admin/organisations/merge_list.html.ep | 25 +++++ 5 files changed, 219 insertions(+) create mode 100644 templates/admin/organisations/merge_detail.html.ep create mode 100644 templates/admin/organisations/merge_list.html.ep diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 59631e7..6b513a1 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -190,6 +190,9 @@ sub startup { $admin_routes->post('/organisations/add')->to('admin-organisations#add_org_submit'); $admin_routes->get('/organisations/:id')->to('admin-organisations#valid_read'); $admin_routes->post('/organisations/:id')->to('admin-organisations#valid_edit'); + $admin_routes->get('/organisations/:id/merge')->to('admin-organisations#merge_list'); + $admin_routes->get('/organisations/:id/merge/:target_id')->to('admin-organisations#merge_detail'); + $admin_routes->post('/organisations/:id/merge/:target_id')->to('admin-organisations#merge_confirm'); $admin_routes->get('/feedback')->to('admin-feedback#index'); $admin_routes->get('/feedback/:id')->to('admin-feedback#read'); diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 2cb3660..8a4eb5f 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -3,6 +3,11 @@ use Mojo::Base 'Mojolicious::Controller'; use Try::Tiny; +has result_set => sub { + my $c = shift; + return $c->schema->resultset('Organisation'); +}; + sub list { my $c = shift; @@ -127,4 +132,104 @@ sub valid_edit { $c->redirect_to( '/admin/organisations/'); } +sub merge_list { + my $c = shift; + + my $org_id = $c->param('id'); + my $org_result = $c->result_set->find($org_id); + + if ( defined $org_result->entity->user ) { + $c->flash( error => 'Cannot merge from user-owned organisation!' ); + $c->redirect_to( '/admin/organisations/' . $org_id ); + return; + } + + my $org_rs = $c->result_set->search( + { + id => { '!=' => $org_id }, + }, + { + page => $c->param('page') || 1, + rows => 10, + order_by => { '-asc' => 'name' }, + } + ); + + $c->stash( + org_result => $org_result, + org_rs => $org_rs, + ); +} + +sub merge_detail { + my $c = shift; + + my $org_id = $c->param('id'); + my $org_result = $c->result_set->find($org_id); + + if ( defined $org_result->entity->user ) { + $c->flash( error => 'Cannot merge from user-owned organisation!' ); + $c->redirect_to( '/admin/organisations/' . $org_id ); + return; + } + + my $target_id = $c->param('target_id'); + my $target_result = $c->result_set->find($target_id); + + unless ( defined $target_result ) { + $c->flash( error => 'Unknown target organisation' ); + $c->redirect_to( '/admin/organisations/' . $org_id . '/merge' ); + return; + } + + $c->stash( + org_result => $org_result, + target_result => $target_result, + ); +} + +sub merge_confirm { + my $c = shift; + + my $org_id = $c->param('id'); + my $org_result = $c->result_set->find($org_id); + + if ( defined $org_result->entity->user ) { + $c->flash( error => 'Cannot merge from user-owned organisation!' ); + $c->redirect_to( '/admin/organisations/' . $org_id ); + return; + } + + my $target_id = $c->param('target_id'); + my $target_result = $c->result_set->find($target_id); + my $confirm = $c->param('confirm'); + + if ( $confirm eq 'checked' && defined $org_result && defined $target_result ) { + try { + $c->schema->txn_do( sub { + # Done as an update, not update_all, so its damn fast - we're only + # editing an id which is guaranteed to be an integer here, and this + # makes it only one update statement. + $org_result->entity->sales->update( + { seller_id => $target_result->entity->id } + ); + my $count = $org_result->entity->sales->count; + die "Failed to migrate all sales" if $count; + $org_result->entity->delete; + $c->schema->resultset('ImportLookup')->search({ entity_id => $org_result->entity->id })->delete; + my $org_count = $c->result_set->search({id => $org_result->id })->count; + my $entity_count = $c->schema->resultset('Entity')->search({id => $org_result->entity->id })->count; + die "Failed to remove org" if $org_count; + die "Failed to remove entity" if $entity_count; + }); + } catch { + $c->app->log->warn($_); + }; + $c->flash( error => 'Engage' ); + } else { + $c->flash( error => 'You must tick the confirmation box to proceed' ); + } + $c->redirect_to( '/admin/organisations/' . $org_id . '/merge/' . $target_id ); +} + 1; diff --git a/lib/Pear/LocalLoop/Plugin/Currency.pm b/lib/Pear/LocalLoop/Plugin/Currency.pm index 842cf89..f256f80 100644 --- a/lib/Pear/LocalLoop/Plugin/Currency.pm +++ b/lib/Pear/LocalLoop/Plugin/Currency.pm @@ -12,6 +12,11 @@ sub register { } return $value; }); + + $app->helper( format_currency_from_db => sub { + my ( $c, $value ) = @_; + return sprintf( '£%.2f', $value / 100000 ); + }); } 1; diff --git a/templates/admin/organisations/merge_detail.html.ep b/templates/admin/organisations/merge_detail.html.ep new file mode 100644 index 0000000..4b3afce --- /dev/null +++ b/templates/admin/organisations/merge_detail.html.ep @@ -0,0 +1,81 @@ +% layout 'admin_errors'; +% title 'Organisations'; +
+
+

Merging <%= $org_result->name %> into <%= $target_result->name %>

+ Back +
+ % for my $org ( $org_result, $target_result ) { +
+
+

+ <%= $org->name %> +

+
+
+
+ Street Name +
+
+ %= $org->street_name +
+
+ Town/City +
+
+ %= $org->town +
+
+ Sector +
+
+ %= $org->sector +
+
+ Postcode +
+
+ %= $org->postcode +
+
+ Validated +
+
+ %= $org->pending ? 'no' : 'yes' +
+
+ Is Local +
+
+ %= $org->is_local ? 'yes' : 'no' +
+
+
+
+
+ Transaction Count: <%= $org->entity->sales->count %> +
+
+
+
+ % } +
+
+
+

+ Warning: Cannot be undone! +

+

+ This will discard all basic information about this organisation, and + merge all transactions into the target organisation. This process has + no way of being undone. +

+
+ + + +
+
+
+
+
diff --git a/templates/admin/organisations/merge_list.html.ep b/templates/admin/organisations/merge_list.html.ep new file mode 100644 index 0000000..0a0dc49 --- /dev/null +++ b/templates/admin/organisations/merge_list.html.ep @@ -0,0 +1,25 @@ +% layout 'admin_errors'; +% title 'Organisations'; +
+
+

Target to merge into for <%= $org_result->name %>

+
+
+
+

+ Organisations + Back +

+
+ % for my $org ( $org_rs->all ) { + + %= $org->name + + % } +
+
+
+
+ %= bootstrap_pagination( $c->param('page') || 1, $org_rs->pager->last_page, { class => 'justify-content-center' } ); +
+
From c3ae7a26154ab809b76ec75b838d0557f8116049 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Mon, 20 Nov 2017 13:02:07 +0000 Subject: [PATCH 010/289] Added badge on organisations showing if they are a user or not --- lib/Pear/LocalLoop/Schema/Result/Organisation.pm | 6 ++++++ templates/admin/organisations/list.html.ep | 3 +++ 2 files changed, 9 insertions(+) diff --git a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm index 630d5fc..98b75c5 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm @@ -123,4 +123,10 @@ sub to_bool { } } +sub user { + my $self = shift; + + return $self->entity->user; +} + 1; diff --git a/templates/admin/organisations/list.html.ep b/templates/admin/organisations/list.html.ep index f0b53ef..6885797 100644 --- a/templates/admin/organisations/list.html.ep +++ b/templates/admin/organisations/list.html.ep @@ -28,6 +28,9 @@ % if ( $org_result->pending ) { Unvalidated % } + % if ( defined $org_result->user ) { + User + % } % if ( !defined $org_result->is_local ) { Locality Not Set % } elsif ( $org_result->is_local ) { From 733107539dd9218b1920829c480bf1f4575afb0a Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Mon, 20 Nov 2017 13:26:52 +0000 Subject: [PATCH 011/289] Added badges to users and pagination --- lib/Pear/LocalLoop/Controller/Admin/Users.pm | 12 ++++++--- templates/admin/users/index.html.ep | 27 +++++++++++++++++--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Users.pm b/lib/Pear/LocalLoop/Controller/Admin/Users.pm index 13905c6..e731d7b 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Users.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Users.pm @@ -22,9 +22,15 @@ has organisation_result_set => sub { sub index { my $c = shift; - my $user_rs = $c->user_result_set; - $user_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); - $c->stash( users => [ $user_rs->all ] ); + my $user_rs = $c->user_result_set->search( + undef, { + prefech => { entity => [ qw/ customer organisation / ] }, + page => $c->param('page') || 1, + rows => 10, + order_by => { -asc => 'email' }, + } + ); + $c->stash( user_rs => $user_rs ); } sub read { diff --git a/templates/admin/users/index.html.ep b/templates/admin/users/index.html.ep index b31330a..0728042 100644 --- a/templates/admin/users/index.html.ep +++ b/templates/admin/users/index.html.ep @@ -12,11 +12,30 @@
% }
- % for my $user (@$users) { - - +
+
+ %= bootstrap_pagination( $c->param('page') || 1, $user_rs->pager->last_page, { class => 'justify-content-center' } ); +
+
From d3a2410507b8ecd87c5735cddf4f57aff95179dc Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Mon, 20 Nov 2017 13:32:10 +0000 Subject: [PATCH 012/289] Updated Changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e5828e..9e1605f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,17 @@ # Next Release +* **Admin Feature** Merged organisation lists into one list * **Admin Feature** Paginated Organisation listings * **Admin Feature** Added flags to Organisations listings * **Admin Feature** Added `is_local` flag to Organisations to start categorising odd stores * **Admin Feature** Feedback items now word wrap * **Admin Feature** Rework transaction viewing +* **Admin Feature** Implemented import method for importing previous data from csv +* **Admin Feature** Added badges for various organisation flags eg. local, user, validated +* **Admin Feature** Enabled merging of organisations to reduce duplicates +* **Admin Feature** Added badges to user listing to show whether customer or organisation +* **Admin Feature** Added pagination to user listings # v0.9.5 From 832dab70cbe14178d54be0ed4204c49cad34bca9 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 21 Nov 2017 10:40:22 +0000 Subject: [PATCH 013/289] dded minor logging to API login endpoint --- lib/Pear/LocalLoop/Controller/Api/Auth.pm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Pear/LocalLoop/Controller/Api/Auth.pm b/lib/Pear/LocalLoop/Controller/Api/Auth.pm index 82cfb60..cf6b466 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Auth.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Auth.pm @@ -74,6 +74,8 @@ sub post_login { my $email = $validation->param('email'); my $password = $validation->param('password'); + $c->app->log->debug( __PACKAGE__ . " login attempt for [" . $email . "]" ); + my $user_result = $c->schema->resultset('User')->find({ email => $email }); if ( defined $user_result ) { @@ -86,6 +88,8 @@ sub post_login { display_name => $user_result->name, user_type => $user_result->type, }); + } else { + $c->app->log->info( __PACKAGE__ . " failed login for [" . $email . "]" ); } } return $c->render( From b92ea1f7c61b88738fbff87bc52d87e05214c4ab Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 21 Nov 2017 10:42:23 +0000 Subject: [PATCH 014/289] Added logging on admin login endpoint --- lib/Pear/LocalLoop/Controller/Admin.pm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Pear/LocalLoop/Controller/Admin.pm b/lib/Pear/LocalLoop/Controller/Admin.pm index 1e5a411..eee9253 100644 --- a/lib/Pear/LocalLoop/Controller/Admin.pm +++ b/lib/Pear/LocalLoop/Controller/Admin.pm @@ -38,9 +38,12 @@ sub home { sub auth_login { my $c = shift; + $c->app->log->debug( __PACKAGE__ . " admin login attempt for [" . $c->param('email') . "]" ); + if ( $c->authenticate($c->param('email'), $c->param('password')) ) { $c->redirect_to('/admin/home'); } else { + $c->app->log->info( __PACKAGE__ . " failed admin login for [" . $c->param('email') . "]" ); $c->redirect_to('/admin'); } } From 8855d64a6ee9579ecfde797ded7133d43d262e8a Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 21 Nov 2017 10:48:32 +0000 Subject: [PATCH 015/289] Fix minor issue in ddl for SQLite --- share/ddl/SQLite/deploy/13/001-auto.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/ddl/SQLite/deploy/13/001-auto.sql b/share/ddl/SQLite/deploy/13/001-auto.sql index 8d1b47b..e54791e 100644 --- a/share/ddl/SQLite/deploy/13/001-auto.sql +++ b/share/ddl/SQLite/deploy/13/001-auto.sql @@ -128,7 +128,7 @@ CREATE TABLE feedback ( package_name varchar(255) NOT NULL, version_code varchar(255) NOT NULL, version_number varchar(255) NOT NULL, - actioned boolean NOT NULL DEFAULT false, + actioned boolean NOT NULL DEFAULT 0, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION ); CREATE INDEX feedback_idx_user_id ON feedback (user_id); From 76a4b2178c6e7e765ecd8a0b5a939522dc8d0d8c Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 21 Nov 2017 11:07:03 +0000 Subject: [PATCH 016/289] Updated Changelog for v0.9.6 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e1605f..34f16b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ # Next Release +# v0.9.6 + * **Admin Feature** Merged organisation lists into one list * **Admin Feature** Paginated Organisation listings * **Admin Feature** Added flags to Organisations listings @@ -13,6 +15,7 @@ * **Admin Feature** Enabled merging of organisations to reduce duplicates * **Admin Feature** Added badges to user listing to show whether customer or organisation * **Admin Feature** Added pagination to user listings +* Improved logging for debugging issues with login # v0.9.5 From d4ad360f38e9c142204fdaeec748cc5800670607 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 21 Nov 2017 11:13:04 +0000 Subject: [PATCH 017/289] Fixed schema issue for import value foreign key being set wrong --- lib/Pear/LocalLoop/Schema/Result/ImportValue.pm | 2 +- share/ddl/PostgreSQL/deploy/14/001-auto.sql | 2 +- share/ddl/PostgreSQL/deploy/15/001-auto.sql | 2 +- share/ddl/PostgreSQL/deploy/16/001-auto.sql | 2 +- share/ddl/PostgreSQL/upgrade/13-14/001-auto.sql | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Pear/LocalLoop/Schema/Result/ImportValue.pm b/lib/Pear/LocalLoop/Schema/Result/ImportValue.pm index a704323..90314c8 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ImportValue.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ImportValue.pm @@ -39,7 +39,7 @@ __PACKAGE__->add_columns( size => 255, }, transaction_id => { - data_type => 'varchar', + data_type => 'integer', is_foreign_key => 1, is_nullable => 1, }, diff --git a/share/ddl/PostgreSQL/deploy/14/001-auto.sql b/share/ddl/PostgreSQL/deploy/14/001-auto.sql index b2583b7..9e3d4be 100644 --- a/share/ddl/PostgreSQL/deploy/14/001-auto.sql +++ b/share/ddl/PostgreSQL/deploy/14/001-auto.sql @@ -206,7 +206,7 @@ CREATE TABLE "import_values" ( "purchase_date" timestamp NOT NULL, "purchase_value" character varying(255) NOT NULL, "org_name" character varying(255) NOT NULL, - "transaction_id" character varying, + "transaction_id" integer, PRIMARY KEY ("id") ); CREATE INDEX "import_values_idx_set_id" on "import_values" ("set_id"); diff --git a/share/ddl/PostgreSQL/deploy/15/001-auto.sql b/share/ddl/PostgreSQL/deploy/15/001-auto.sql index 552946d..86ca07f 100644 --- a/share/ddl/PostgreSQL/deploy/15/001-auto.sql +++ b/share/ddl/PostgreSQL/deploy/15/001-auto.sql @@ -206,7 +206,7 @@ CREATE TABLE "import_values" ( "purchase_date" timestamp NOT NULL, "purchase_value" character varying(255) NOT NULL, "org_name" character varying(255) NOT NULL, - "transaction_id" character varying, + "transaction_id" integer, "ignore_value" boolean DEFAULT false NOT NULL, PRIMARY KEY ("id") ); diff --git a/share/ddl/PostgreSQL/deploy/16/001-auto.sql b/share/ddl/PostgreSQL/deploy/16/001-auto.sql index 5a2f6dd..45aedba 100644 --- a/share/ddl/PostgreSQL/deploy/16/001-auto.sql +++ b/share/ddl/PostgreSQL/deploy/16/001-auto.sql @@ -220,7 +220,7 @@ CREATE TABLE "import_values" ( "purchase_date" timestamp NOT NULL, "purchase_value" character varying(255) NOT NULL, "org_name" character varying(255) NOT NULL, - "transaction_id" character varying, + "transaction_id" integer, "ignore_value" boolean DEFAULT false NOT NULL, PRIMARY KEY ("id") ); diff --git a/share/ddl/PostgreSQL/upgrade/13-14/001-auto.sql b/share/ddl/PostgreSQL/upgrade/13-14/001-auto.sql index d440b3e..6856826 100644 --- a/share/ddl/PostgreSQL/upgrade/13-14/001-auto.sql +++ b/share/ddl/PostgreSQL/upgrade/13-14/001-auto.sql @@ -18,7 +18,7 @@ CREATE TABLE "import_values" ( "purchase_date" timestamp NOT NULL, "purchase_value" character varying(255) NOT NULL, "org_name" character varying(255) NOT NULL, - "transaction_id" character varying, + "transaction_id" integer, PRIMARY KEY ("id") ); CREATE INDEX "import_values_idx_set_id" on "import_values" ("set_id"); From f5b94098fb7d26bd2766941cf8f938cdf8b72aa0 Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 23 Nov 2017 13:20:26 +0000 Subject: [PATCH 018/289] Entity Assoiciations added to database --- lib/Pear/LocalLoop/Schema/Result/Entity.pm | 7 ++++ .../Schema/Result/EntityAssociation.pm | 39 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm diff --git a/lib/Pear/LocalLoop/Schema/Result/Entity.pm b/lib/Pear/LocalLoop/Schema/Result/Entity.pm index aa3df1b..7f1a7c9 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Entity.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Entity.pm @@ -44,6 +44,13 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); +__PACKAGE__->has_many( + "associations", + "Pear::LocalLoop::Schema::Result::EntityAssociation", + { "foreign.entity_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + __PACKAGE__->has_many( "sales", "Pear::LocalLoop::Schema::Result::Transaction", diff --git a/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm new file mode 100644 index 0000000..d547722 --- /dev/null +++ b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm @@ -0,0 +1,39 @@ +package Pear::LocalLoop::Schema::Result::EntityAssociation; + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +__PACKAGE__->load_components(qw/ + InflateColumn::DateTime + TimeStamp +/); + +__PACKAGE__->table("entity_association"); + +__PACKAGE__->add_columns( + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "entity_id" => { + data_type => 'integer', + is_nullable => 0, + is_foreign_key => 1, + }, + "lis" => { + data_type => 'boolean', + default => undef, + is_nullable => 1, + }, +); + +__PACKAGE__->set_primary_key("id"); + +__PACKAGE__->belongs_to( + "entity", + "Pear::LocalLoop::Schema::Result::Entity", + "entity_id", +); From a4b307ad6c90626799ced75b28eecc12f492ca19 Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 23 Nov 2017 14:54:59 +0000 Subject: [PATCH 019/289] database upgraded and interface added --- .../Controller/Admin/Organisations.pm | 4 +- lib/Pear/LocalLoop/Schema.pm | 2 +- lib/Pear/LocalLoop/Schema/Result/Entity.pm | 12 +- .../Schema/Result/EntityAssociation.pm | 5 - .../deploy/17/001-auto-__VERSION.sql | 18 + share/ddl/PostgreSQL/deploy/17/001-auto.sql | 328 ++++ .../ddl/PostgreSQL/upgrade/16-17/001-auto.sql | 25 + .../SQLite/deploy/17/001-auto-__VERSION.sql | 18 + share/ddl/SQLite/deploy/17/001-auto.sql | 228 +++ share/ddl/SQLite/upgrade/16-17/001-auto.sql | 66 + .../_source/deploy/17/001-auto-__VERSION.yml | 91 + share/ddl/_source/deploy/17/001-auto.yml | 1714 +++++++++++++++++ .../admin/organisations/valid_read.html.ep | 9 + 13 files changed, 2506 insertions(+), 14 deletions(-) create mode 100644 share/ddl/PostgreSQL/deploy/17/001-auto-__VERSION.sql create mode 100644 share/ddl/PostgreSQL/deploy/17/001-auto.sql create mode 100644 share/ddl/PostgreSQL/upgrade/16-17/001-auto.sql create mode 100644 share/ddl/SQLite/deploy/17/001-auto-__VERSION.sql create mode 100644 share/ddl/SQLite/deploy/17/001-auto.sql create mode 100644 share/ddl/SQLite/upgrade/16-17/001-auto.sql create mode 100644 share/ddl/_source/deploy/17/001-auto-__VERSION.yml create mode 100644 share/ddl/_source/deploy/17/001-auto.yml diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 8a4eb5f..d4f3999 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -85,9 +85,11 @@ sub valid_read { order_by => { -desc => 'submitted_at' }, }, ); + my $associations = $valid_org->entity->associations; $c->stash( valid_org => $valid_org, transactions => $transactions, + associations => $associations, ); } @@ -143,7 +145,7 @@ sub merge_list { $c->redirect_to( '/admin/organisations/' . $org_id ); return; } - + my $org_rs = $c->result_set->search( { id => { '!=' => $org_id }, diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index ce98e85..4816a75 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -6,7 +6,7 @@ use warnings; use base 'DBIx::Class::Schema'; -our $VERSION = 16; +our $VERSION = 17; __PACKAGE__->load_namespaces; diff --git a/lib/Pear/LocalLoop/Schema/Result/Entity.pm b/lib/Pear/LocalLoop/Schema/Result/Entity.pm index 7f1a7c9..3839a71 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Entity.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Entity.pm @@ -37,6 +37,11 @@ __PACKAGE__->might_have( "Pear::LocalLoop::Schema::Result::User" => "entity_id", ); +__PACKAGE__->might_have( +"associations", + "Pear::LocalLoop::Schema::Result::EntityAssociation" => "entity_id", +); + __PACKAGE__->has_many( "purchases", "Pear::LocalLoop::Schema::Result::Transaction", @@ -44,13 +49,6 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); -__PACKAGE__->has_many( - "associations", - "Pear::LocalLoop::Schema::Result::EntityAssociation", - { "foreign.entity_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, -); - __PACKAGE__->has_many( "sales", "Pear::LocalLoop::Schema::Result::Transaction", diff --git a/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm index d547722..442adb5 100644 --- a/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm @@ -5,11 +5,6 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components(qw/ - InflateColumn::DateTime - TimeStamp -/); - __PACKAGE__->table("entity_association"); __PACKAGE__->add_columns( diff --git a/share/ddl/PostgreSQL/deploy/17/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/17/001-auto-__VERSION.sql new file mode 100644 index 0000000..e9095e1 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/17/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Thu Nov 23 14:08:17 2017 +-- +; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE "dbix_class_deploymenthandler_versions" ( + "id" serial NOT NULL, + "version" character varying(50) NOT NULL, + "ddl" text, + "upgrade_sql" text, + PRIMARY KEY ("id"), + CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version") +); + +; diff --git a/share/ddl/PostgreSQL/deploy/17/001-auto.sql b/share/ddl/PostgreSQL/deploy/17/001-auto.sql new file mode 100644 index 0000000..6f939fd --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/17/001-auto.sql @@ -0,0 +1,328 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Thu Nov 23 14:08:16 2017 +-- +; +-- +-- Table: account_tokens +-- +CREATE TABLE "account_tokens" ( + "id" serial NOT NULL, + "name" text NOT NULL, + "used" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "account_tokens_name" UNIQUE ("name") +); + +; +-- +-- Table: entities +-- +CREATE TABLE "entities" ( + "id" serial NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: gb_postcodes +-- +CREATE TABLE "gb_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) DEFAULT '' NOT NULL, + "latitude" numeric(7,5), + "longitude" numeric(7,5), + PRIMARY KEY ("outcode", "incode") +); + +; +-- +-- Table: import_sets +-- +CREATE TABLE "import_sets" ( + "id" serial NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: leaderboards +-- +CREATE TABLE "leaderboards" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboards_type" UNIQUE ("type") +); + +; +-- +-- Table: customers +-- +CREATE TABLE "customers" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "display_name" character varying(255) NOT NULL, + "full_name" character varying(255) NOT NULL, + "year_of_birth" integer NOT NULL, + "postcode" character varying(16) NOT NULL, + "latitude" numeric(5,2), + "longitude" numeric(5,2), + PRIMARY KEY ("id") +); +CREATE INDEX "customers_idx_entity_id" on "customers" ("entity_id"); + +; +-- +-- Table: entity_association +-- +CREATE TABLE "entity_association" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "lis" boolean, + PRIMARY KEY ("id") +); +CREATE INDEX "entity_association_idx_entity_id" on "entity_association" ("entity_id"); + +; +-- +-- Table: leaderboard_sets +-- +CREATE TABLE "leaderboard_sets" ( + "id" serial NOT NULL, + "leaderboard_id" integer NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "leaderboard_sets_idx_leaderboard_id" on "leaderboard_sets" ("leaderboard_id"); + +; +-- +-- Table: organisations +-- +CREATE TABLE "organisations" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "street_name" text, + "town" character varying(255) NOT NULL, + "postcode" character varying(16), + "country" character varying(255), + "sector" character varying(1), + "pending" boolean DEFAULT false NOT NULL, + "is_local" boolean, + "submitted_by_id" integer, + "latitude" numeric(8,5), + "longitude" numeric(8,5), + PRIMARY KEY ("id") +); +CREATE INDEX "organisations_idx_entity_id" on "organisations" ("entity_id"); + +; +-- +-- Table: transactions +-- +CREATE TABLE "transactions" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "proof_image" text, + "submitted_at" timestamp NOT NULL, + "purchase_time" timestamp NOT NULL, + "distance" numeric(15), + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_idx_buyer_id" on "transactions" ("buyer_id"); +CREATE INDEX "transactions_idx_seller_id" on "transactions" ("seller_id"); + +; +-- +-- Table: users +-- +CREATE TABLE "users" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "email" text NOT NULL, + "join_date" timestamp NOT NULL, + "password" character varying(100) NOT NULL, + "is_admin" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "users_email" UNIQUE ("email") +); +CREATE INDEX "users_idx_entity_id" on "users" ("entity_id"); + +; +-- +-- Table: feedback +-- +CREATE TABLE "feedback" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "feedbacktext" text NOT NULL, + "app_name" character varying(255) NOT NULL, + "package_name" character varying(255) NOT NULL, + "version_code" character varying(255) NOT NULL, + "version_number" character varying(255) NOT NULL, + "actioned" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "feedback_idx_user_id" on "feedback" ("user_id"); + +; +-- +-- Table: import_lookups +-- +CREATE TABLE "import_lookups" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_lookups_idx_entity_id" on "import_lookups" ("entity_id"); +CREATE INDEX "import_lookups_idx_set_id" on "import_lookups" ("set_id"); + +; +-- +-- Table: organisation_payroll +-- +CREATE TABLE "organisation_payroll" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "entry_period" timestamp NOT NULL, + "employee_amount" integer NOT NULL, + "local_employee_amount" integer NOT NULL, + "gross_payroll" numeric(100,0) NOT NULL, + "payroll_income_tax" numeric(100,0) NOT NULL, + "payroll_employee_ni" numeric(100,0) NOT NULL, + "payroll_employer_ni" numeric(100,0) NOT NULL, + "payroll_total_pension" numeric(100,0) NOT NULL, + "payroll_other_benefit" numeric(100,0) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisation_payroll_idx_org_id" on "organisation_payroll" ("org_id"); + +; +-- +-- Table: session_tokens +-- +CREATE TABLE "session_tokens" ( + "id" serial NOT NULL, + "token" character varying(255) NOT NULL, + "user_id" integer NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "session_tokens_token" UNIQUE ("token") +); +CREATE INDEX "session_tokens_idx_user_id" on "session_tokens" ("user_id"); + +; +-- +-- Table: import_values +-- +CREATE TABLE "import_values" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "user_name" character varying(255) NOT NULL, + "purchase_date" timestamp NOT NULL, + "purchase_value" character varying(255) NOT NULL, + "org_name" character varying(255) NOT NULL, + "transaction_id" integer, + "ignore_value" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_values_idx_set_id" on "import_values" ("set_id"); +CREATE INDEX "import_values_idx_transaction_id" on "import_values" ("transaction_id"); + +; +-- +-- Table: leaderboard_values +-- +CREATE TABLE "leaderboard_values" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "set_id" integer NOT NULL, + "position" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "trend" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboard_values_entity_id_set_id" UNIQUE ("entity_id", "set_id") +); +CREATE INDEX "leaderboard_values_idx_entity_id" on "leaderboard_values" ("entity_id"); +CREATE INDEX "leaderboard_values_idx_set_id" on "leaderboard_values" ("set_id"); + +; +-- +-- Foreign Key Definitions +-- + +; +ALTER TABLE "customers" ADD CONSTRAINT "customers_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entity_association" ADD CONSTRAINT "entity_association_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "leaderboard_sets" ADD CONSTRAINT "leaderboard_sets_fk_leaderboard_id" FOREIGN KEY ("leaderboard_id") + REFERENCES "leaderboards" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "users" ADD CONSTRAINT "users_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "feedback" ADD CONSTRAINT "feedback_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisation_payroll" ADD CONSTRAINT "organisation_payroll_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") DEFERRABLE; + +; +ALTER TABLE "session_tokens" ADD CONSTRAINT "session_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "leaderboard_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; diff --git a/share/ddl/PostgreSQL/upgrade/16-17/001-auto.sql b/share/ddl/PostgreSQL/upgrade/16-17/001-auto.sql new file mode 100644 index 0000000..1984d67 --- /dev/null +++ b/share/ddl/PostgreSQL/upgrade/16-17/001-auto.sql @@ -0,0 +1,25 @@ +-- Convert schema 'share/ddl/_source/deploy/16/001-auto.yml' to 'share/ddl/_source/deploy/17/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE "entity_association" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "lis" boolean, + PRIMARY KEY ("id") +); +CREATE INDEX "entity_association_idx_entity_id" on "entity_association" ("entity_id"); + +; +ALTER TABLE "entity_association" ADD CONSTRAINT "entity_association_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE import_values ALTER COLUMN transaction_id TYPE integer; + +; + +COMMIT; + diff --git a/share/ddl/SQLite/deploy/17/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/17/001-auto-__VERSION.sql new file mode 100644 index 0000000..0b3f8f3 --- /dev/null +++ b/share/ddl/SQLite/deploy/17/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Thu Nov 23 14:08:17 2017 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE dbix_class_deploymenthandler_versions ( + id INTEGER PRIMARY KEY NOT NULL, + version varchar(50) NOT NULL, + ddl text, + upgrade_sql text +); +CREATE UNIQUE INDEX dbix_class_deploymenthandler_versions_version ON dbix_class_deploymenthandler_versions (version); +COMMIT; diff --git a/share/ddl/SQLite/deploy/17/001-auto.sql b/share/ddl/SQLite/deploy/17/001-auto.sql new file mode 100644 index 0000000..280d016 --- /dev/null +++ b/share/ddl/SQLite/deploy/17/001-auto.sql @@ -0,0 +1,228 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Thu Nov 23 14:08:17 2017 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: account_tokens +-- +CREATE TABLE account_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + name text NOT NULL, + used integer NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX account_tokens_name ON account_tokens (name); +-- +-- Table: entities +-- +CREATE TABLE entities ( + id INTEGER PRIMARY KEY NOT NULL, + type varchar(255) NOT NULL +); +-- +-- Table: gb_postcodes +-- +CREATE TABLE gb_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL DEFAULT '', + latitude decimal(7,5), + longitude decimal(7,5), + PRIMARY KEY (outcode, incode) +); +-- +-- Table: import_sets +-- +CREATE TABLE import_sets ( + id INTEGER PRIMARY KEY NOT NULL, + date datetime NOT NULL +); +-- +-- Table: leaderboards +-- +CREATE TABLE leaderboards ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + type varchar(255) NOT NULL +); +CREATE UNIQUE INDEX leaderboards_type ON leaderboards (type); +-- +-- Table: customers +-- +CREATE TABLE customers ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + display_name varchar(255) NOT NULL, + full_name varchar(255) NOT NULL, + year_of_birth integer NOT NULL, + postcode varchar(16) NOT NULL, + latitude decimal(5,2), + longitude decimal(5,2), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX customers_idx_entity_id ON customers (entity_id); +-- +-- Table: entity_association +-- +CREATE TABLE entity_association ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + lis boolean, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX entity_association_idx_entity_id ON entity_association (entity_id); +-- +-- Table: leaderboard_sets +-- +CREATE TABLE leaderboard_sets ( + id INTEGER PRIMARY KEY NOT NULL, + leaderboard_id integer NOT NULL, + date datetime NOT NULL, + FOREIGN KEY (leaderboard_id) REFERENCES leaderboards(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_sets_idx_leaderboard_id ON leaderboard_sets (leaderboard_id); +-- +-- Table: organisations +-- +CREATE TABLE organisations ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + name varchar(255) NOT NULL, + street_name text, + town varchar(255) NOT NULL, + postcode varchar(16), + country varchar(255), + sector varchar(1), + pending boolean NOT NULL DEFAULT false, + is_local boolean, + submitted_by_id integer, + latitude decimal(8,5), + longitude decimal(8,5), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX organisations_idx_entity_id ON organisations (entity_id); +-- +-- Table: transactions +-- +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + distance numeric(15), + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transactions_idx_buyer_id ON transactions (buyer_id); +CREATE INDEX transactions_idx_seller_id ON transactions (seller_id); +-- +-- Table: users +-- +CREATE TABLE users ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + email text NOT NULL, + join_date datetime NOT NULL, + password varchar(100) NOT NULL, + is_admin boolean NOT NULL DEFAULT false, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX users_idx_entity_id ON users (entity_id); +CREATE UNIQUE INDEX users_email ON users (email); +-- +-- Table: feedback +-- +CREATE TABLE feedback ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + submitted_at datetime NOT NULL, + feedbacktext text NOT NULL, + app_name varchar(255) NOT NULL, + package_name varchar(255) NOT NULL, + version_code varchar(255) NOT NULL, + version_number varchar(255) NOT NULL, + actioned boolean NOT NULL DEFAULT false, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX feedback_idx_user_id ON feedback (user_id); +-- +-- Table: import_lookups +-- +CREATE TABLE import_lookups ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + name varchar(255) NOT NULL, + entity_id integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_lookups_idx_entity_id ON import_lookups (entity_id); +CREATE INDEX import_lookups_idx_set_id ON import_lookups (set_id); +-- +-- Table: organisation_payroll +-- +CREATE TABLE organisation_payroll ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + submitted_at datetime NOT NULL, + entry_period datetime NOT NULL, + employee_amount integer NOT NULL, + local_employee_amount integer NOT NULL, + gross_payroll numeric(100,0) NOT NULL, + payroll_income_tax numeric(100,0) NOT NULL, + payroll_employee_ni numeric(100,0) NOT NULL, + payroll_employer_ni numeric(100,0) NOT NULL, + payroll_total_pension numeric(100,0) NOT NULL, + payroll_other_benefit numeric(100,0) NOT NULL, + FOREIGN KEY (org_id) REFERENCES organisations(id) +); +CREATE INDEX organisation_payroll_idx_org_id ON organisation_payroll (org_id); +-- +-- Table: session_tokens +-- +CREATE TABLE session_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + token varchar(255) NOT NULL, + user_id integer NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX session_tokens_idx_user_id ON session_tokens (user_id); +CREATE UNIQUE INDEX session_tokens_token ON session_tokens (token); +-- +-- Table: import_values +-- +CREATE TABLE import_values ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + user_name varchar(255) NOT NULL, + purchase_date datetime NOT NULL, + purchase_value varchar(255) NOT NULL, + org_name varchar(255) NOT NULL, + transaction_id integer, + ignore_value boolean NOT NULL DEFAULT false, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_values_idx_set_id ON import_values (set_id); +CREATE INDEX import_values_idx_transaction_id ON import_values (transaction_id); +-- +-- Table: leaderboard_values +-- +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_values_idx_entity_id ON leaderboard_values (entity_id); +CREATE INDEX leaderboard_values_idx_set_id ON leaderboard_values (set_id); +CREATE UNIQUE INDEX leaderboard_values_entity_id_set_id ON leaderboard_values (entity_id, set_id); +COMMIT; diff --git a/share/ddl/SQLite/upgrade/16-17/001-auto.sql b/share/ddl/SQLite/upgrade/16-17/001-auto.sql new file mode 100644 index 0000000..e4db9ba --- /dev/null +++ b/share/ddl/SQLite/upgrade/16-17/001-auto.sql @@ -0,0 +1,66 @@ +-- Convert schema 'share/ddl/_source/deploy/16/001-auto.yml' to 'share/ddl/_source/deploy/17/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE entity_association ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + lis boolean, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); + +; +CREATE INDEX entity_association_idx_entity_id ON entity_association (entity_id); + +; +CREATE TEMPORARY TABLE import_values_temp_alter ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + user_name varchar(255) NOT NULL, + purchase_date datetime NOT NULL, + purchase_value varchar(255) NOT NULL, + org_name varchar(255) NOT NULL, + transaction_id integer, + ignore_value boolean NOT NULL DEFAULT false, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); + +; +INSERT INTO import_values_temp_alter( id, set_id, user_name, purchase_date, purchase_value, org_name, transaction_id, ignore_value) SELECT id, set_id, user_name, purchase_date, purchase_value, org_name, transaction_id, ignore_value FROM import_values; + +; +DROP TABLE import_values; + +; +CREATE TABLE import_values ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + user_name varchar(255) NOT NULL, + purchase_date datetime NOT NULL, + purchase_value varchar(255) NOT NULL, + org_name varchar(255) NOT NULL, + transaction_id integer, + ignore_value boolean NOT NULL DEFAULT false, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); + +; +CREATE INDEX import_values_idx_set_id02 ON import_values (set_id); + +; +CREATE INDEX import_values_idx_transacti00 ON import_values (transaction_id); + +; +INSERT INTO import_values SELECT id, set_id, user_name, purchase_date, purchase_value, org_name, transaction_id, ignore_value FROM import_values_temp_alter; + +; +DROP TABLE import_values_temp_alter; + +; + +COMMIT; + diff --git a/share/ddl/_source/deploy/17/001-auto-__VERSION.yml b/share/ddl/_source/deploy/17/001-auto-__VERSION.yml new file mode 100644 index 0000000..907f443 --- /dev/null +++ b/share/ddl/_source/deploy/17/001-auto-__VERSION.yml @@ -0,0 +1,91 @@ +--- +schema: + procedures: {} + tables: + dbix_class_deploymenthandler_versions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - version + match_type: '' + name: dbix_class_deploymenthandler_versions_version + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + ddl: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ddl + order: 3 + size: + - 0 + id: + data_type: int + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + upgrade_sql: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: upgrade_sql + order: 4 + size: + - 0 + version: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: version + order: 2 + size: + - 50 + indices: [] + name: dbix_class_deploymenthandler_versions + options: [] + order: 1 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - __VERSION + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 diff --git a/share/ddl/_source/deploy/17/001-auto.yml b/share/ddl/_source/deploy/17/001-auto.yml new file mode 100644 index 0000000..cea995e --- /dev/null +++ b/share/ddl/_source/deploy/17/001-auto.yml @@ -0,0 +1,1714 @@ +--- +schema: + procedures: {} + tables: + account_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: account_tokens_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 0 + used: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: used + order: 3 + size: + - 0 + indices: [] + name: account_tokens + options: [] + order: 1 + customers: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: customers_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + display_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: display_name + order: 3 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + full_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 4 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 7 + size: + - 5 + - 2 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 8 + size: + - 5 + - 2 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + year_of_birth: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: year_of_birth + order: 5 + size: + - 0 + indices: + - fields: + - entity_id + name: customers_idx_entity_id + options: [] + type: NORMAL + name: customers + options: [] + order: 6 + entities: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: type + order: 2 + size: + - 255 + indices: [] + name: entities + options: [] + order: 2 + entity_association: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entity_association_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + lis: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: lis + order: 3 + size: + - 0 + indices: + - fields: + - entity_id + name: entity_association_idx_entity_id + options: [] + type: NORMAL + name: entity_association + options: [] + order: 7 + feedback: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: feedback_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + actioned: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: actioned + order: 9 + size: + - 0 + app_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: app_name + order: 5 + size: + - 255 + feedbacktext: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: feedbacktext + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + package_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: package_name + order: 6 + size: + - 255 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + version_code: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_code + order: 7 + size: + - 255 + version_number: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_number + order: 8 + size: + - 255 + indices: + - fields: + - user_id + name: feedback_idx_user_id + options: [] + type: NORMAL + name: feedback + options: [] + order: 12 + gb_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + incode: + data_type: char + default_value: '' + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 3 + size: + - 7 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 4 + size: + - 7 + - 5 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + indices: [] + name: gb_postcodes + options: [] + order: 3 + import_lookups: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: import_lookups_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_lookups_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + indices: + - fields: + - entity_id + name: import_lookups_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: import_lookups_idx_set_id + options: [] + type: NORMAL + name: import_lookups + options: [] + order: 13 + import_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: import_sets + options: [] + order: 4 + import_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: import_values_fk_transaction_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ignore_value: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ignore_value + order: 8 + size: + - 0 + org_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_name + order: 6 + size: + - 255 + purchase_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_date + order: 4 + size: + - 0 + purchase_value: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_value + order: 5 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 7 + size: + - 0 + user_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_name + order: 3 + size: + - 255 + indices: + - fields: + - set_id + name: import_values_idx_set_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: import_values_idx_transaction_id + options: [] + type: NORMAL + name: import_values + options: [] + order: 16 + leaderboard_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - leaderboard_id + match_type: '' + name: leaderboard_sets_fk_leaderboard_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboards + type: FOREIGN KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + leaderboard_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: leaderboard_id + order: 2 + size: + - 0 + indices: + - fields: + - leaderboard_id + name: leaderboard_sets_idx_leaderboard_id + options: [] + type: NORMAL + name: leaderboard_sets + options: [] + order: 8 + leaderboard_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + - set_id + match_type: '' + name: leaderboard_values_entity_id_set_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - entity_id + match_type: '' + name: leaderboard_values_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: leaderboard_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboard_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + position: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: position + order: 4 + size: + - 0 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: set_id + order: 3 + size: + - 0 + trend: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: trend + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 5 + size: + - 100 + - 0 + indices: + - fields: + - entity_id + name: leaderboard_values_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: leaderboard_values_idx_set_id + options: [] + type: NORMAL + name: leaderboard_values + options: [] + order: 17 + leaderboards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - type + match_type: '' + name: leaderboards_type + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 255 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: type + order: 3 + size: + - 255 + indices: [] + name: leaderboards + options: [] + order: 5 + organisation_payroll: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisation_payroll_fk_org_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: employee_amount + order: 5 + size: + - 0 + entry_period: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entry_period + order: 4 + size: + - 0 + gross_payroll: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_payroll + order: 7 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_employee_amount + order: 6 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + payroll_employee_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employee_ni + order: 9 + size: + - 100 + - 0 + payroll_employer_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employer_ni + order: 10 + size: + - 100 + - 0 + payroll_income_tax: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_income_tax + order: 8 + size: + - 100 + - 0 + payroll_other_benefit: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_other_benefit + order: 12 + size: + - 100 + - 0 + payroll_total_pension: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_total_pension + order: 11 + size: + - 100 + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + indices: + - fields: + - org_id + name: organisation_payroll_idx_org_id + options: [] + type: NORMAL + name: organisation_payroll + options: [] + order: 14 + organisations: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: organisations_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + country: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: country + order: 7 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_local: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_local + order: 10 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 12 + size: + - 8 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 13 + size: + - 8 + - 5 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + pending: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: pending + order: 9 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + sector: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: sector + order: 8 + size: + - 1 + street_name: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: street_name + order: 4 + size: + - 0 + submitted_by_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: submitted_by_id + order: 11 + size: + - 0 + town: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: town + order: 5 + size: + - 255 + indices: + - fields: + - entity_id + name: organisations_idx_entity_id + options: [] + type: NORMAL + name: organisations + options: [] + order: 9 + session_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - token + match_type: '' + name: session_tokens_token + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: session_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: token + order: 2 + size: + - 255 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 3 + size: + - 0 + indices: + - fields: + - user_id + name: session_tokens_idx_user_id + options: [] + type: NORMAL + name: session_tokens + options: [] + order: 15 + transactions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transactions_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transactions_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 8 + size: + - 15 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + proof_image: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: proof_image + order: 5 + size: + - 0 + purchase_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_time + order: 7 + size: + - 0 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transactions_idx_buyer_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transactions_idx_seller_id + options: [] + type: NORMAL + name: transactions + options: [] + order: 10 + users: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: users_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: users_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 3 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_admin: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_admin + order: 6 + size: + - 0 + join_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: join_date + order: 4 + size: + - 0 + password: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: password + order: 5 + size: + - 100 + indices: + - fields: + - entity_id + name: users_idx_entity_id + options: [] + type: NORMAL + name: users + options: [] + order: 11 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - AccountToken + - Customer + - Entity + - EntityAssociation + - Feedback + - GbPostcode + - ImportLookup + - ImportSet + - ImportValue + - Leaderboard + - LeaderboardSet + - LeaderboardValue + - Organisation + - OrganisationPayroll + - SessionToken + - Transaction + - User + - ViewQuantisedTransactionPg + - ViewQuantisedTransactionSQLite + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 diff --git a/templates/admin/organisations/valid_read.html.ep b/templates/admin/organisations/valid_read.html.ep index 046f3f9..e605fa8 100644 --- a/templates/admin/organisations/valid_read.html.ep +++ b/templates/admin/organisations/valid_read.html.ep @@ -99,6 +99,15 @@ function initMap() { value="0"<%= $valid_org->pending ? '' : ' checked' %>>
+
+ +
+ +
+
From 8754ffd93a11a46f2eaa97be33cc382b69c6539d Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 23 Nov 2017 15:42:37 +0000 Subject: [PATCH 020/289] endpoint and code added for LIS orgs --- lib/Pear/LocalLoop.pm | 1 + .../Controller/Api/V1/Supplier/Location.pm | 70 ++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 6b513a1..1dd9f9a 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -158,6 +158,7 @@ sub startup { my $api_v1_supplier = $api_v1->under('/supplier'); $api_v1_supplier->post('/location')->to('api-v1-supplier-location#index'); + $api_v1_supplier->post('/location/lis')->to('api-v1-supplier-location#lis_load'); my $api_v1_org = $api_v1->under('/organisation')->to('api-v1-organisation#auth'); diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm index accd3af..5b5187d 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm @@ -86,7 +86,7 @@ sub index { $org_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); - my $suppliers = [ map { + my $suppliers = [ map { { latitude => $_->{organisation}->{latitude} * 1, longitude => $_->{organisation}->{longitude} * 1, @@ -106,4 +106,72 @@ sub index { ); } +sub lis_load { + my $c = shift; + + return if $c->validation_error('index'); + + my $json = $c->stash->{api_json}; + + # Extra custom error, because its funny + if ( $json->{north_east}->{latitude} < $json->{south_west}->{latitude} ) { + return $c->render( + json => { + success => Mojo::JSON->false, + errors => [ 'upside_down' ], + }, + status => 400, + ); + } + + my $entity = $c->stash->{api_user}->entity; + my $entity_type_object = $entity->type_object; + my $orgs_lis = $valid_org = $c->schema->resultset('Entity')->find( $c->param('lis') ); + + # need: organisations only, with name, latitude, and longitude + my $org_rs = $orgs_lis->associations->search_related('entity', + { + 'entity.type' => 'organisation', + 'organisation.latitude' => { -between => [ + $json->{south_west}->{latitude}, + $json->{north_east}->{latitude}, + ] }, + 'organisation.longitude' => { -between => [ + $json->{south_west}->{longitude}, + $json->{north_east}->{longitude}, + ] }, + }, + { + join => [ qw/ organisation / ], + columns => [ + 'organisation.name', + 'organisation.latitude', + 'organisation.longitude', + ], + group_by => [ qw/ organisation.id / ], + }, + ); + + $org_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); + + my $suppliers = [ map { + { + latitude => $_->{organisation}->{latitude} * 1, + longitude => $_->{organisation}->{longitude} * 1, + name => $_->{organisation}->{name}, + } + } $org_rs->all ]; + + $c->render( + json => { + success => Mojo::JSON->true, + locations => $locations, + self => { + latitude => $entity_type_object->latitude, + longitude => $entity_type_object->longitude, + } + }, + ); +} + 1; From 54dcbf6fb8ccde69986bd4a7d1002290ef4cec8c Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 23 Nov 2017 16:25:14 +0000 Subject: [PATCH 021/289] fixes added and working admin interface --- lib/Pear/LocalLoop/Controller/Admin/Organisations.pm | 12 ++++++++++-- .../LocalLoop/Controller/Api/V1/Supplier/Location.pm | 10 +++++++--- templates/admin/organisations/valid_read.html.ep | 8 ++++---- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index d4f3999..4ce41b6 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -86,10 +86,14 @@ sub valid_read { }, ); my $associations = $valid_org->entity->associations; + my $assoc = { + lis => defined $associations ? $associations->lis : 0, + }; + $c->stash( valid_org => $valid_org, transactions => $transactions, - associations => $associations, + associations => $assoc, ); } @@ -104,6 +108,7 @@ sub valid_edit { $validation->required('postcode')->postcode; $validation->optional('pending'); $validation->optional('is_local'); + $validation->optional('is_lis'); if ( $validation->has_error ) { $c->flash( error => 'The validation has failed' ); @@ -123,9 +128,12 @@ sub valid_edit { pending => defined $validation->param('pending') ? 0 : 1, is_local => $validation->param('is_local'), }); + $valid_org->entity->update_or_create_related( 'associations', { + lis => $validation->param('is_lis'), + }); } ); } finally { - if ( @_ ) { + if ( @_ ) {use Devel::Dwarn; Dwarn \@_; $c->flash( error => 'Something went wrong Updating the Organisation' ); } else { $c->flash( success => 'Updated Organisation' ); diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm index 5b5187d..08e8601 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm @@ -126,10 +126,14 @@ sub lis_load { my $entity = $c->stash->{api_user}->entity; my $entity_type_object = $entity->type_object; - my $orgs_lis = $valid_org = $c->schema->resultset('Entity')->find( $c->param('lis') ); + my $orgs_lis = $c->schema->resultset('EntityAssociation')->search( + { + 'lis' => 1, + }, + ); # need: organisations only, with name, latitude, and longitude - my $org_rs = $orgs_lis->associations->search_related('entity', + my $org_rs = $orgs_lis->search_related('entity', { 'entity.type' => 'organisation', 'organisation.latitude' => { -between => [ @@ -154,7 +158,7 @@ sub lis_load { $org_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); - my $suppliers = [ map { + my $locations = [ map { { latitude => $_->{organisation}->{latitude} * 1, longitude => $_->{organisation}->{longitude} * 1, diff --git a/templates/admin/organisations/valid_read.html.ep b/templates/admin/organisations/valid_read.html.ep index e605fa8..9f590e8 100644 --- a/templates/admin/organisations/valid_read.html.ep +++ b/templates/admin/organisations/valid_read.html.ep @@ -100,11 +100,11 @@ function initMap() {
- +
- + +
From 96a9b152d1c72f1db8cd02d5d7f8d7af473495ee Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 23 Nov 2017 16:35:45 +0000 Subject: [PATCH 022/289] extra org data added --- lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm index 08e8601..73efcf3 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm @@ -151,6 +151,9 @@ sub lis_load { 'organisation.name', 'organisation.latitude', 'organisation.longitude', + 'organisation.street_name', + 'organisation.town', + 'organisation.postcode', ], group_by => [ qw/ organisation.id / ], }, @@ -163,6 +166,9 @@ sub lis_load { latitude => $_->{organisation}->{latitude} * 1, longitude => $_->{organisation}->{longitude} * 1, name => $_->{organisation}->{name}, + street_name => $_->{organisation}->{street_name}, + town => $_->{organisation}->{town}, + postcode => $_->{organisation}->{postcode}, } } $org_rs->all ]; From d718cfee42487aea38de536e6187b587143184f1 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Thu, 23 Nov 2017 16:52:33 +0000 Subject: [PATCH 023/289] Fixed issue with Importset for users and orgs trying to much data for the group by --- .../LocalLoop/Schema/ResultSet/ImportSet.pm | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm b/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm index 785aa99..2ef3e75 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm @@ -23,12 +23,28 @@ sub get_values { ); } +sub _unordered_get_values { + my $self = shift; + my $id = shift; + my $include_ignored = shift; + my $include_imported = shift; + + return $self->find($id)->search_related( + 'values', + { + ( $include_ignored ? () : ( ignore_value => 0 ) ), + ( $include_imported ? () : ( transaction_id => undef ) ), + }, + ); +} + sub get_users { my $self = shift; - return $self->get_values(@_)->search({}, + return $self->_unordered_get_values(@_)->search({}, { group_by => 'user_name', + columns => [ qw/ user_name / ], }, ); } @@ -36,9 +52,10 @@ sub get_users { sub get_orgs { my $self = shift; - return $self->get_values(@_)->search({}, + return $self->_unordered_get_values(@_)->search({}, { group_by => 'org_name', + columns => [ qw/ org_name / ], }, ); } From 9d8db81f2f746e96792828e807d369fed3544d17 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Thu, 23 Nov 2017 16:52:52 +0000 Subject: [PATCH 024/289] Fix dev_data Command for testing --- lib/Pear/LocalLoop/Command/dev_data.pm | 54 ++++++++++++++++---------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/lib/Pear/LocalLoop/Command/dev_data.pm b/lib/Pear/LocalLoop/Command/dev_data.pm index 70a5673..5cf079b 100644 --- a/lib/Pear/LocalLoop/Command/dev_data.pm +++ b/lib/Pear/LocalLoop/Command/dev_data.pm @@ -28,45 +28,57 @@ sub run { $schema->resultset('User')->create({ email => 'test@example.com', password => 'abc123', - customer => { - full_name => 'Test User', - display_name => 'Test User', - year_of_birth => 2006, - postcode => 'LA1 1AA', + entity => { + type => 'customer', + customer => { + full_name => 'Test User', + display_name => 'Test User', + year_of_birth => 2006, + postcode => 'LA1 1AA', + } }, - administrator => {}, + is_admin => 1, }); $schema->resultset('User')->create({ email => 'test2@example.com', password => 'abc123', - customer => { - full_name => 'Test User 2', - display_name => 'Test User 2', - year_of_birth => 2006, - postcode => 'LA1 1AA', + entity => { + type => 'customer', + customer => { + full_name => 'Test User 2', + display_name => 'Test User 2', + year_of_birth => 2006, + postcode => 'LA1 1AA', + }, }, }); $schema->resultset('User')->create({ email => 'test3@example.com', password => 'abc123', - customer => { - full_name => 'Test User 3', - display_name => 'Test User 3', - year_of_birth => 2006, - postcode => 'LA1 1AA', + entity => { + type => 'customer', + customer => { + full_name => 'Test User 3', + display_name => 'Test User 3', + year_of_birth => 2006, + postcode => 'LA1 1AA', + }, }, }); $schema->resultset('User')->create({ email => 'testorg@example.com', password => 'abc123', - organisation => { - name => 'Test Org', - street_name => 'Test Street', - town => 'Lancaster', - postcode => 'LA1 1AA', + entity => { + type => 'organisation', + organisation => { + name => 'Test Org', + street_name => 'Test Street', + town => 'Lancaster', + postcode => 'LA1 1AA', + }, }, }); } From 8c48e490fc69ab7b21ee5982a6d45ad4570adc0c Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Thu, 23 Nov 2017 17:18:07 +0000 Subject: [PATCH 025/289] Updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34f16b9..72fee9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ # Next Release +* **Admin Fix**: Fix error in Importing under Postgres + # v0.9.6 * **Admin Feature** Merged organisation lists into one list From 850bd3d7110257d87bd71fc5c65d50c7d5dc0644 Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 23 Nov 2017 17:19:21 +0000 Subject: [PATCH 026/289] changelog updated --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34f16b9..466dbbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ # Next Release +* **Admin Feature** Ability to add entity to LIS Added +* Added code endpoint for LIS organisations for web app use +* Schema updated to account for these changes + # v0.9.6 * **Admin Feature** Merged organisation lists into one list From 3f0f046c30093ad1febb62b7ec70bfc60d080112 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 27 Nov 2017 11:36:21 +0000 Subject: [PATCH 027/289] added location info to main map --- lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm index 73efcf3..2ca7ebc 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm @@ -91,6 +91,9 @@ sub index { latitude => $_->{organisation}->{latitude} * 1, longitude => $_->{organisation}->{longitude} * 1, name => $_->{organisation}->{name}, + street_name => $_->{organisation}->{street_name}, + town => $_->{organisation}->{town}, + postcode => $_->{organisation}->{postcode}, } } $org_rs->all ]; From f68479b5acfee9f437db42d5a1806707a1e67b91 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 27 Nov 2017 17:16:22 +0000 Subject: [PATCH 028/289] extra info fixed and test amended and fixtures changed --- .../Controller/Api/V1/Supplier/Location.pm | 3 + t/api/v1/supplier/location.t | 3 + t/etc/fixtures/config/full.pl | 12 ++-- t/etc/fixtures/data/full/_config_set | 64 +++++++++++++------ .../data/full/entity_association/1.fix | 6 ++ .../data/full/gb_postcodes/LA2-0AA.fix | 2 +- t/etc/fixtures/data/full/organisations/1.fix | 1 + t/etc/fixtures/data/full/organisations/2.fix | 1 + 8 files changed, 66 insertions(+), 26 deletions(-) create mode 100644 t/etc/fixtures/data/full/entity_association/1.fix diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm index 2ca7ebc..9ffb0d4 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm @@ -79,6 +79,9 @@ sub index { 'organisation.name', 'organisation.latitude', 'organisation.longitude', + 'organisation.street_name', + 'organisation.town', + 'organisation.postcode', ], group_by => [ qw/ organisation.id / ], }, diff --git a/t/api/v1/supplier/location.t b/t/api/v1/supplier/location.t index 7b7794a..89b277a 100644 --- a/t/api/v1/supplier/location.t +++ b/t/api/v1/supplier/location.t @@ -49,6 +49,9 @@ $t->post_ok('/api/v1/supplier/location' => json => { name => 'Test Org 2', latitude => 54.04679, longitude => -2.7963, + street_name => 'Test Street', + town => 'Lancaster', + postcode => 'LA1 1AG', }, ]) ->json_is('/self', { diff --git a/t/etc/fixtures/config/full.pl b/t/etc/fixtures/config/full.pl index 61c9c5e..c1959cb 100644 --- a/t/etc/fixtures/config/full.pl +++ b/t/etc/fixtures/config/full.pl @@ -99,8 +99,8 @@ street_name => 'Test Street', town => 'Lancaster', postcode => 'LA1 1AF', - latitude => 54.04725, - longitude => -2.79611, + latitude => 54.04725, + longitude => -2.79611, }, user => { email => 'org1@example.com', @@ -115,13 +115,16 @@ street_name => 'Test Street', town => 'Lancaster', postcode => 'LA1 1AG', - latitude => 54.04679, - longitude => -2.7963, + latitude => 54.04679, + longitude => -2.7963, }, user => { email => 'org2@example.com', password => 'abc123', }, + associations => { + lis => 1, + }, type => "organisation", }; @@ -207,4 +210,3 @@ schema => $schema, directory => "$Bin/../data/" . $data_set, }); - diff --git a/t/etc/fixtures/data/full/_config_set b/t/etc/fixtures/data/full/_config_set index bc4099f..d2fde35 100644 --- a/t/etc/fixtures/data/full/_config_set +++ b/t/etc/fixtures/data/full/_config_set @@ -2,64 +2,88 @@ $VAR1 = { 'has_many' => { 'fetch' => 0 }, + 'belongs_to' => { + 'fetch' => 0 + }, + 'might_have' => { + 'fetch' => 0 + }, 'sets' => [ { - 'class' => 'OrganisationPayroll', + 'class' => 'EntityAssociation', 'quantity' => 'all' }, { 'quantity' => 'all', - 'class' => 'User' + 'class' => 'ViewQuantisedTransactionPg' + }, + { + 'class' => 'OrganisationPayroll', + 'quantity' => 'all' }, { 'quantity' => 'all', - 'class' => 'Customer' + 'class' => 'Feedback' }, { - 'class' => 'Entity', + 'class' => 'LeaderboardValue', 'quantity' => 'all' }, { 'quantity' => 'all', - 'class' => 'LeaderboardValue' + 'class' => 'GbPostcode' }, { 'quantity' => 'all', - 'class' => 'Feedback' + 'class' => 'SessionToken' }, { - 'class' => 'Organisation', + 'quantity' => 'all', + 'class' => 'ViewQuantisedTransactionSQLite' + }, + { + 'class' => 'LeaderboardSet', 'quantity' => 'all' }, { - 'class' => 'GbPostcode', + 'class' => 'ImportSet', 'quantity' => 'all' }, { 'quantity' => 'all', - 'class' => 'LeaderboardSet' + 'class' => 'ImportValue' }, { - 'quantity' => 'all', - 'class' => 'AccountToken' + 'class' => 'AccountToken', + 'quantity' => 'all' }, { 'quantity' => 'all', - 'class' => 'SessionToken' + 'class' => 'Leaderboard' }, { 'quantity' => 'all', 'class' => 'Transaction' }, { - 'class' => 'Leaderboard', + 'quantity' => 'all', + 'class' => 'Organisation' + }, + { + 'class' => 'Customer', + 'quantity' => 'all' + }, + { + 'class' => 'ImportLookup', + 'quantity' => 'all' + }, + { + 'class' => 'Entity', 'quantity' => 'all' + }, + { + 'quantity' => 'all', + 'class' => 'User' } - ], - 'belongs_to' => { - 'fetch' => 0 - }, - 'might_have' => { - 'fetch' => 0 - } + ] }; diff --git a/t/etc/fixtures/data/full/entity_association/1.fix b/t/etc/fixtures/data/full/entity_association/1.fix new file mode 100644 index 0000000..47c930a --- /dev/null +++ b/t/etc/fixtures/data/full/entity_association/1.fix @@ -0,0 +1,6 @@ +$HASH1 = { + entity_id + => 6, + id => 1, + lis => 1 + }; diff --git a/t/etc/fixtures/data/full/gb_postcodes/LA2-0AA.fix b/t/etc/fixtures/data/full/gb_postcodes/LA2-0AA.fix index 3b6c044..7009876 100644 --- a/t/etc/fixtures/data/full/gb_postcodes/LA2-0AA.fix +++ b/t/etc/fixtures/data/full/gb_postcodes/LA2-0AA.fix @@ -1,6 +1,6 @@ $HASH1 = { incode => '0AA', latitude => 54.02493, - longitude => -2.80717, + longitude => -2.80718, outcode => 'LA2' }; diff --git a/t/etc/fixtures/data/full/organisations/1.fix b/t/etc/fixtures/data/full/organisations/1.fix index b9ce32d..21968dd 100644 --- a/t/etc/fixtures/data/full/organisations/1.fix +++ b/t/etc/fixtures/data/full/organisations/1.fix @@ -3,6 +3,7 @@ $HASH1 = { entity_id => 5, id => 1, + is_local => undef, latitude => 54.04725, longitude => -2.79611, diff --git a/t/etc/fixtures/data/full/organisations/2.fix b/t/etc/fixtures/data/full/organisations/2.fix index 8702817..631eea2 100644 --- a/t/etc/fixtures/data/full/organisations/2.fix +++ b/t/etc/fixtures/data/full/organisations/2.fix @@ -3,6 +3,7 @@ $HASH1 = { entity_id => 6, id => 2, + is_local => undef, latitude => 54.04679, longitude => -2.7963, From 361e0e359cfcfaec4fb5ddc1c865e5e85470fdd7 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 27 Nov 2017 17:17:22 +0000 Subject: [PATCH 029/289] test fixed --- t/api/v1/supplier/location.t | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/api/v1/supplier/location.t b/t/api/v1/supplier/location.t index 89b277a..032c716 100644 --- a/t/api/v1/supplier/location.t +++ b/t/api/v1/supplier/location.t @@ -59,4 +59,32 @@ $t->post_ok('/api/v1/supplier/location' => json => { longitude => -2.79611, }); + $t->post_ok('/api/v1/supplier/location/lis' => json => { + session_key => $session_key, + north_east => { + latitude => 54.077665, + longitude => -2.761860, + }, + south_west => { + latitude => 54.013361, + longitude => -2.857647, + }, + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->true) + ->json_is('/locations', [ + { + name => 'Test Org 2', + latitude => 54.04679, + longitude => -2.7963, + street_name => 'Test Street', + town => 'Lancaster', + postcode => 'LA1 1AG', + }, + ]) + ->json_is('/self', { + latitude => 54.04725, + longitude => -2.79611, + }); + done_testing; From 6e7527d6bdc6c0256be6c9a4e6278b965d09c6eb Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Tue, 28 Nov 2017 18:33:58 +0000 Subject: [PATCH 030/289] Updated changelog for 0.9.7 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index be80974..a38acbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ # Next Release +# v0.9.7 + * **Admin Fix**: Fix error in Importing under Postgres * **Admin Feature** Ability to add entity to LIS Added * Added code endpoint for LIS organisations for web app use From 36cd695ed58ad14ba69b77027e454398a0c03bee Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 29 Nov 2017 16:24:03 +0000 Subject: [PATCH 031/289] Amended validation on orgs --- lib/Pear/LocalLoop/Controller/Admin/Organisations.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 4ce41b6..140acd7 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -102,7 +102,7 @@ sub valid_edit { my $validation = $c->validation; $validation->required('name'); - $validation->required('street_name'); + $validation->optional('street_name'); $validation->required('town'); $validation->optional('sector'); $validation->required('postcode')->postcode; From e926d40779974fc27f17e0791a5f337f36233bae Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 4 Dec 2017 12:27:53 +0000 Subject: [PATCH 032/289] added new tab linking and corrected redirect --- lib/Pear/LocalLoop/Controller/Admin/Organisations.pm | 2 +- templates/admin/organisations/list.html.ep | 4 ++-- templates/admin/organisations/valid_read.html.ep | 2 +- templates/admin/transactions/index.html.ep | 2 +- templates/admin/users/index.html.ep | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 4ce41b6..23f4577 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -139,7 +139,7 @@ sub valid_edit { $c->flash( success => 'Updated Organisation' ); } }; - $c->redirect_to( '/admin/organisations/'); + $c->redirect_to( '/admin/organisations/' . $c->param('id') ); } sub merge_list { diff --git a/templates/admin/organisations/list.html.ep b/templates/admin/organisations/list.html.ep index 6885797..eca8aed 100644 --- a/templates/admin/organisations/list.html.ep +++ b/templates/admin/organisations/list.html.ep @@ -16,11 +16,11 @@

Organisations - Add Organisation + Add Organisation

% for my $org_result ($orgs_rs->all) { - +
%= $org_result->name
diff --git a/templates/admin/organisations/valid_read.html.ep b/templates/admin/organisations/valid_read.html.ep index 9f590e8..5b6d934 100644 --- a/templates/admin/organisations/valid_read.html.ep +++ b/templates/admin/organisations/valid_read.html.ep @@ -148,7 +148,7 @@ function initMap() {
% for my $transaction ( $transactions->all ) { - +
From: <%= $transaction->buyer->name %>
To: <%= $transaction->seller->name %>
diff --git a/templates/admin/transactions/index.html.ep b/templates/admin/transactions/index.html.ep index b20ad2b..3ebb83a 100644 --- a/templates/admin/transactions/index.html.ep +++ b/templates/admin/transactions/index.html.ep @@ -19,7 +19,7 @@
% for my $transaction ( $transactions->all ) { - +
diff --git a/templates/admin/users/index.html.ep b/templates/admin/users/index.html.ep index 0728042..35db20e 100644 --- a/templates/admin/users/index.html.ep +++ b/templates/admin/users/index.html.ep @@ -13,7 +13,7 @@ % }
% for my $user ($user_rs->all) { - +
%= $user->name From d8403b8b118578839a1f8feaf0b3732412ae88da Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 4 Dec 2017 12:27:53 +0000 Subject: [PATCH 033/289] Revert "added new tab linking and corrected redirect" This reverts commit 4eb5a4fd3f14ecc6870bf8fc9f3e1da0d73eff8f. --- lib/Pear/LocalLoop/Controller/Admin/Organisations.pm | 2 +- templates/admin/organisations/list.html.ep | 4 ++-- templates/admin/organisations/valid_read.html.ep | 2 +- templates/admin/transactions/index.html.ep | 2 +- templates/admin/users/index.html.ep | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 23f4577..4ce41b6 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -139,7 +139,7 @@ sub valid_edit { $c->flash( success => 'Updated Organisation' ); } }; - $c->redirect_to( '/admin/organisations/' . $c->param('id') ); + $c->redirect_to( '/admin/organisations/'); } sub merge_list { diff --git a/templates/admin/organisations/list.html.ep b/templates/admin/organisations/list.html.ep index eca8aed..6885797 100644 --- a/templates/admin/organisations/list.html.ep +++ b/templates/admin/organisations/list.html.ep @@ -16,11 +16,11 @@

Organisations - Add Organisation + Add Organisation

% for my $org_result ($orgs_rs->all) { - +
%= $org_result->name
diff --git a/templates/admin/organisations/valid_read.html.ep b/templates/admin/organisations/valid_read.html.ep index 5b6d934..9f590e8 100644 --- a/templates/admin/organisations/valid_read.html.ep +++ b/templates/admin/organisations/valid_read.html.ep @@ -148,7 +148,7 @@ function initMap() {
% for my $transaction ( $transactions->all ) { - +
From: <%= $transaction->buyer->name %>
To: <%= $transaction->seller->name %>
diff --git a/templates/admin/transactions/index.html.ep b/templates/admin/transactions/index.html.ep index 3ebb83a..b20ad2b 100644 --- a/templates/admin/transactions/index.html.ep +++ b/templates/admin/transactions/index.html.ep @@ -19,7 +19,7 @@
% for my $transaction ( $transactions->all ) { - +
diff --git a/templates/admin/users/index.html.ep b/templates/admin/users/index.html.ep index 35db20e..0728042 100644 --- a/templates/admin/users/index.html.ep +++ b/templates/admin/users/index.html.ep @@ -13,7 +13,7 @@ % }
% for my $user ($user_rs->all) { - +
%= $user->name From 0b48c696124e1b99adf6f0e39ae7479e151cda6c Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 4 Dec 2017 12:27:53 +0000 Subject: [PATCH 034/289] added new tab linking and corrected redirect --- lib/Pear/LocalLoop/Controller/Admin/Organisations.pm | 2 +- templates/admin/organisations/list.html.ep | 4 ++-- templates/admin/organisations/valid_read.html.ep | 2 +- templates/admin/transactions/index.html.ep | 2 +- templates/admin/users/index.html.ep | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 4ce41b6..23f4577 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -139,7 +139,7 @@ sub valid_edit { $c->flash( success => 'Updated Organisation' ); } }; - $c->redirect_to( '/admin/organisations/'); + $c->redirect_to( '/admin/organisations/' . $c->param('id') ); } sub merge_list { diff --git a/templates/admin/organisations/list.html.ep b/templates/admin/organisations/list.html.ep index 6885797..eca8aed 100644 --- a/templates/admin/organisations/list.html.ep +++ b/templates/admin/organisations/list.html.ep @@ -16,11 +16,11 @@

Organisations - Add Organisation + Add Organisation

% for my $org_result ($orgs_rs->all) { - +
%= $org_result->name
diff --git a/templates/admin/organisations/valid_read.html.ep b/templates/admin/organisations/valid_read.html.ep index 9f590e8..5b6d934 100644 --- a/templates/admin/organisations/valid_read.html.ep +++ b/templates/admin/organisations/valid_read.html.ep @@ -148,7 +148,7 @@ function initMap() {
% for my $transaction ( $transactions->all ) { - +
From: <%= $transaction->buyer->name %>
To: <%= $transaction->seller->name %>
diff --git a/templates/admin/transactions/index.html.ep b/templates/admin/transactions/index.html.ep index b20ad2b..3ebb83a 100644 --- a/templates/admin/transactions/index.html.ep +++ b/templates/admin/transactions/index.html.ep @@ -19,7 +19,7 @@
% for my $transaction ( $transactions->all ) { - +
diff --git a/templates/admin/users/index.html.ep b/templates/admin/users/index.html.ep index 0728042..35db20e 100644 --- a/templates/admin/users/index.html.ep +++ b/templates/admin/users/index.html.ep @@ -13,7 +13,7 @@ % }
% for my $user ($user_rs->all) { - +
%= $user->name From af7dcde7aac5995941fdace26103c48ea498d0f0 Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 8 Dec 2017 12:30:49 +0000 Subject: [PATCH 035/289] esta added to schema and updated admin interface --- CHANGELOG.md | 3 +++ .../LocalLoop/Controller/Admin/Organisations.pm | 3 +++ .../LocalLoop/Schema/Result/EntityAssociation.pm | 5 +++++ templates/admin/organisations/valid_read.html.ep | 13 +++++++++++-- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a38acbb..2e8616d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ # Next Release +* **Admin Feature** Improved links in relevant places to automatically open in + a new tab + # v0.9.7 * **Admin Fix**: Fix error in Importing under Postgres diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 0382bc4..7a42d10 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -88,6 +88,7 @@ sub valid_read { my $associations = $valid_org->entity->associations; my $assoc = { lis => defined $associations ? $associations->lis : 0, + esta => defined $associations ? $associations->esta : 0, }; $c->stash( @@ -109,6 +110,7 @@ sub valid_edit { $validation->optional('pending'); $validation->optional('is_local'); $validation->optional('is_lis'); + $validation->optional('is_esta'); if ( $validation->has_error ) { $c->flash( error => 'The validation has failed' ); @@ -130,6 +132,7 @@ sub valid_edit { }); $valid_org->entity->update_or_create_related( 'associations', { lis => $validation->param('is_lis'), + esta => $validation->param('is_esta') }); } ); } finally { diff --git a/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm index 442adb5..f4c0744 100644 --- a/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm @@ -23,6 +23,11 @@ __PACKAGE__->add_columns( default => undef, is_nullable => 1, }, + "esta" => { + data_type => 'boolean', + default => undef, + is_nullable => 1, + }, ); __PACKAGE__->set_primary_key("id"); diff --git a/templates/admin/organisations/valid_read.html.ep b/templates/admin/organisations/valid_read.html.ep index 5b6d934..5341659 100644 --- a/templates/admin/organisations/valid_read.html.ep +++ b/templates/admin/organisations/valid_read.html.ep @@ -103,8 +103,17 @@ function initMap() {
+
+
+
+ +
+
From cd59547311dd07d1cff0bd193e6b71f88aea1759 Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 8 Dec 2017 13:19:22 +0000 Subject: [PATCH 036/289] schema and map code updated, test fixed --- lib/Pear/LocalLoop.pm | 2 +- .../Controller/Api/V1/Supplier/Location.pm | 4 +- lib/Pear/LocalLoop/Schema.pm | 2 +- .../deploy/18/001-auto-__VERSION.sql | 18 + share/ddl/PostgreSQL/deploy/18/001-auto.sql | 329 ++++ .../ddl/PostgreSQL/upgrade/17-18/001-auto.sql | 12 + .../SQLite/deploy/18/001-auto-__VERSION.sql | 18 + share/ddl/SQLite/deploy/18/001-auto.sql | 229 +++ share/ddl/SQLite/upgrade/17-18/001-auto.sql | 12 + .../_source/deploy/18/001-auto-__VERSION.yml | 91 + share/ddl/_source/deploy/18/001-auto.yml | 1724 +++++++++++++++++ t/api/v1/supplier/location.t | 4 +- t/etc/fixtures/config/full.pl | 1 + 13 files changed, 2441 insertions(+), 5 deletions(-) create mode 100644 share/ddl/PostgreSQL/deploy/18/001-auto-__VERSION.sql create mode 100644 share/ddl/PostgreSQL/deploy/18/001-auto.sql create mode 100644 share/ddl/PostgreSQL/upgrade/17-18/001-auto.sql create mode 100644 share/ddl/SQLite/deploy/18/001-auto-__VERSION.sql create mode 100644 share/ddl/SQLite/deploy/18/001-auto.sql create mode 100644 share/ddl/SQLite/upgrade/17-18/001-auto.sql create mode 100644 share/ddl/_source/deploy/18/001-auto-__VERSION.yml create mode 100644 share/ddl/_source/deploy/18/001-auto.yml diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 1dd9f9a..1e13f09 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -158,7 +158,7 @@ sub startup { my $api_v1_supplier = $api_v1->under('/supplier'); $api_v1_supplier->post('/location')->to('api-v1-supplier-location#index'); - $api_v1_supplier->post('/location/lis')->to('api-v1-supplier-location#lis_load'); + $api_v1_supplier->post('/location/trail')->to('api-v1-supplier-location#trail_load'); my $api_v1_org = $api_v1->under('/organisation')->to('api-v1-organisation#auth'); diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm index 9ffb0d4..c90539b 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm @@ -112,7 +112,7 @@ sub index { ); } -sub lis_load { +sub trail_load { my $c = shift; return if $c->validation_error('index'); @@ -134,7 +134,7 @@ sub lis_load { my $entity_type_object = $entity->type_object; my $orgs_lis = $c->schema->resultset('EntityAssociation')->search( { - 'lis' => 1, + $json->{association} => 1, }, ); diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index 4816a75..2d35b1b 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -6,7 +6,7 @@ use warnings; use base 'DBIx::Class::Schema'; -our $VERSION = 17; +our $VERSION = 18; __PACKAGE__->load_namespaces; diff --git a/share/ddl/PostgreSQL/deploy/18/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/18/001-auto-__VERSION.sql new file mode 100644 index 0000000..7e49cc3 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/18/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Fri Dec 8 13:18:16 2017 +-- +; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE "dbix_class_deploymenthandler_versions" ( + "id" serial NOT NULL, + "version" character varying(50) NOT NULL, + "ddl" text, + "upgrade_sql" text, + PRIMARY KEY ("id"), + CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version") +); + +; diff --git a/share/ddl/PostgreSQL/deploy/18/001-auto.sql b/share/ddl/PostgreSQL/deploy/18/001-auto.sql new file mode 100644 index 0000000..5017c32 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/18/001-auto.sql @@ -0,0 +1,329 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Fri Dec 8 13:18:16 2017 +-- +; +-- +-- Table: account_tokens +-- +CREATE TABLE "account_tokens" ( + "id" serial NOT NULL, + "name" text NOT NULL, + "used" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "account_tokens_name" UNIQUE ("name") +); + +; +-- +-- Table: entities +-- +CREATE TABLE "entities" ( + "id" serial NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: gb_postcodes +-- +CREATE TABLE "gb_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) DEFAULT '' NOT NULL, + "latitude" numeric(7,5), + "longitude" numeric(7,5), + PRIMARY KEY ("outcode", "incode") +); + +; +-- +-- Table: import_sets +-- +CREATE TABLE "import_sets" ( + "id" serial NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: leaderboards +-- +CREATE TABLE "leaderboards" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboards_type" UNIQUE ("type") +); + +; +-- +-- Table: customers +-- +CREATE TABLE "customers" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "display_name" character varying(255) NOT NULL, + "full_name" character varying(255) NOT NULL, + "year_of_birth" integer NOT NULL, + "postcode" character varying(16) NOT NULL, + "latitude" numeric(5,2), + "longitude" numeric(5,2), + PRIMARY KEY ("id") +); +CREATE INDEX "customers_idx_entity_id" on "customers" ("entity_id"); + +; +-- +-- Table: entity_association +-- +CREATE TABLE "entity_association" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "lis" boolean, + "esta" boolean, + PRIMARY KEY ("id") +); +CREATE INDEX "entity_association_idx_entity_id" on "entity_association" ("entity_id"); + +; +-- +-- Table: leaderboard_sets +-- +CREATE TABLE "leaderboard_sets" ( + "id" serial NOT NULL, + "leaderboard_id" integer NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "leaderboard_sets_idx_leaderboard_id" on "leaderboard_sets" ("leaderboard_id"); + +; +-- +-- Table: organisations +-- +CREATE TABLE "organisations" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "street_name" text, + "town" character varying(255) NOT NULL, + "postcode" character varying(16), + "country" character varying(255), + "sector" character varying(1), + "pending" boolean DEFAULT false NOT NULL, + "is_local" boolean, + "submitted_by_id" integer, + "latitude" numeric(8,5), + "longitude" numeric(8,5), + PRIMARY KEY ("id") +); +CREATE INDEX "organisations_idx_entity_id" on "organisations" ("entity_id"); + +; +-- +-- Table: transactions +-- +CREATE TABLE "transactions" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "proof_image" text, + "submitted_at" timestamp NOT NULL, + "purchase_time" timestamp NOT NULL, + "distance" numeric(15), + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_idx_buyer_id" on "transactions" ("buyer_id"); +CREATE INDEX "transactions_idx_seller_id" on "transactions" ("seller_id"); + +; +-- +-- Table: users +-- +CREATE TABLE "users" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "email" text NOT NULL, + "join_date" timestamp NOT NULL, + "password" character varying(100) NOT NULL, + "is_admin" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "users_email" UNIQUE ("email") +); +CREATE INDEX "users_idx_entity_id" on "users" ("entity_id"); + +; +-- +-- Table: feedback +-- +CREATE TABLE "feedback" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "feedbacktext" text NOT NULL, + "app_name" character varying(255) NOT NULL, + "package_name" character varying(255) NOT NULL, + "version_code" character varying(255) NOT NULL, + "version_number" character varying(255) NOT NULL, + "actioned" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "feedback_idx_user_id" on "feedback" ("user_id"); + +; +-- +-- Table: import_lookups +-- +CREATE TABLE "import_lookups" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_lookups_idx_entity_id" on "import_lookups" ("entity_id"); +CREATE INDEX "import_lookups_idx_set_id" on "import_lookups" ("set_id"); + +; +-- +-- Table: organisation_payroll +-- +CREATE TABLE "organisation_payroll" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "entry_period" timestamp NOT NULL, + "employee_amount" integer NOT NULL, + "local_employee_amount" integer NOT NULL, + "gross_payroll" numeric(100,0) NOT NULL, + "payroll_income_tax" numeric(100,0) NOT NULL, + "payroll_employee_ni" numeric(100,0) NOT NULL, + "payroll_employer_ni" numeric(100,0) NOT NULL, + "payroll_total_pension" numeric(100,0) NOT NULL, + "payroll_other_benefit" numeric(100,0) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisation_payroll_idx_org_id" on "organisation_payroll" ("org_id"); + +; +-- +-- Table: session_tokens +-- +CREATE TABLE "session_tokens" ( + "id" serial NOT NULL, + "token" character varying(255) NOT NULL, + "user_id" integer NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "session_tokens_token" UNIQUE ("token") +); +CREATE INDEX "session_tokens_idx_user_id" on "session_tokens" ("user_id"); + +; +-- +-- Table: import_values +-- +CREATE TABLE "import_values" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "user_name" character varying(255) NOT NULL, + "purchase_date" timestamp NOT NULL, + "purchase_value" character varying(255) NOT NULL, + "org_name" character varying(255) NOT NULL, + "transaction_id" integer, + "ignore_value" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_values_idx_set_id" on "import_values" ("set_id"); +CREATE INDEX "import_values_idx_transaction_id" on "import_values" ("transaction_id"); + +; +-- +-- Table: leaderboard_values +-- +CREATE TABLE "leaderboard_values" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "set_id" integer NOT NULL, + "position" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "trend" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboard_values_entity_id_set_id" UNIQUE ("entity_id", "set_id") +); +CREATE INDEX "leaderboard_values_idx_entity_id" on "leaderboard_values" ("entity_id"); +CREATE INDEX "leaderboard_values_idx_set_id" on "leaderboard_values" ("set_id"); + +; +-- +-- Foreign Key Definitions +-- + +; +ALTER TABLE "customers" ADD CONSTRAINT "customers_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entity_association" ADD CONSTRAINT "entity_association_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "leaderboard_sets" ADD CONSTRAINT "leaderboard_sets_fk_leaderboard_id" FOREIGN KEY ("leaderboard_id") + REFERENCES "leaderboards" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "users" ADD CONSTRAINT "users_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "feedback" ADD CONSTRAINT "feedback_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisation_payroll" ADD CONSTRAINT "organisation_payroll_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") DEFERRABLE; + +; +ALTER TABLE "session_tokens" ADD CONSTRAINT "session_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "leaderboard_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; diff --git a/share/ddl/PostgreSQL/upgrade/17-18/001-auto.sql b/share/ddl/PostgreSQL/upgrade/17-18/001-auto.sql new file mode 100644 index 0000000..f22ef95 --- /dev/null +++ b/share/ddl/PostgreSQL/upgrade/17-18/001-auto.sql @@ -0,0 +1,12 @@ +-- Convert schema 'share/ddl/_source/deploy/17/001-auto.yml' to 'share/ddl/_source/deploy/18/001-auto.yml':; + +; +BEGIN; + +; +ALTER TABLE entity_association ADD COLUMN esta boolean; + +; + +COMMIT; + diff --git a/share/ddl/SQLite/deploy/18/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/18/001-auto-__VERSION.sql new file mode 100644 index 0000000..e7fe88f --- /dev/null +++ b/share/ddl/SQLite/deploy/18/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Fri Dec 8 13:18:16 2017 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE dbix_class_deploymenthandler_versions ( + id INTEGER PRIMARY KEY NOT NULL, + version varchar(50) NOT NULL, + ddl text, + upgrade_sql text +); +CREATE UNIQUE INDEX dbix_class_deploymenthandler_versions_version ON dbix_class_deploymenthandler_versions (version); +COMMIT; diff --git a/share/ddl/SQLite/deploy/18/001-auto.sql b/share/ddl/SQLite/deploy/18/001-auto.sql new file mode 100644 index 0000000..bcdd2dd --- /dev/null +++ b/share/ddl/SQLite/deploy/18/001-auto.sql @@ -0,0 +1,229 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Fri Dec 8 13:18:16 2017 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: account_tokens +-- +CREATE TABLE account_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + name text NOT NULL, + used integer NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX account_tokens_name ON account_tokens (name); +-- +-- Table: entities +-- +CREATE TABLE entities ( + id INTEGER PRIMARY KEY NOT NULL, + type varchar(255) NOT NULL +); +-- +-- Table: gb_postcodes +-- +CREATE TABLE gb_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL DEFAULT '', + latitude decimal(7,5), + longitude decimal(7,5), + PRIMARY KEY (outcode, incode) +); +-- +-- Table: import_sets +-- +CREATE TABLE import_sets ( + id INTEGER PRIMARY KEY NOT NULL, + date datetime NOT NULL +); +-- +-- Table: leaderboards +-- +CREATE TABLE leaderboards ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + type varchar(255) NOT NULL +); +CREATE UNIQUE INDEX leaderboards_type ON leaderboards (type); +-- +-- Table: customers +-- +CREATE TABLE customers ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + display_name varchar(255) NOT NULL, + full_name varchar(255) NOT NULL, + year_of_birth integer NOT NULL, + postcode varchar(16) NOT NULL, + latitude decimal(5,2), + longitude decimal(5,2), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX customers_idx_entity_id ON customers (entity_id); +-- +-- Table: entity_association +-- +CREATE TABLE entity_association ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + lis boolean, + esta boolean, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX entity_association_idx_entity_id ON entity_association (entity_id); +-- +-- Table: leaderboard_sets +-- +CREATE TABLE leaderboard_sets ( + id INTEGER PRIMARY KEY NOT NULL, + leaderboard_id integer NOT NULL, + date datetime NOT NULL, + FOREIGN KEY (leaderboard_id) REFERENCES leaderboards(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_sets_idx_leaderboard_id ON leaderboard_sets (leaderboard_id); +-- +-- Table: organisations +-- +CREATE TABLE organisations ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + name varchar(255) NOT NULL, + street_name text, + town varchar(255) NOT NULL, + postcode varchar(16), + country varchar(255), + sector varchar(1), + pending boolean NOT NULL DEFAULT false, + is_local boolean, + submitted_by_id integer, + latitude decimal(8,5), + longitude decimal(8,5), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX organisations_idx_entity_id ON organisations (entity_id); +-- +-- Table: transactions +-- +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + distance numeric(15), + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transactions_idx_buyer_id ON transactions (buyer_id); +CREATE INDEX transactions_idx_seller_id ON transactions (seller_id); +-- +-- Table: users +-- +CREATE TABLE users ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + email text NOT NULL, + join_date datetime NOT NULL, + password varchar(100) NOT NULL, + is_admin boolean NOT NULL DEFAULT false, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX users_idx_entity_id ON users (entity_id); +CREATE UNIQUE INDEX users_email ON users (email); +-- +-- Table: feedback +-- +CREATE TABLE feedback ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + submitted_at datetime NOT NULL, + feedbacktext text NOT NULL, + app_name varchar(255) NOT NULL, + package_name varchar(255) NOT NULL, + version_code varchar(255) NOT NULL, + version_number varchar(255) NOT NULL, + actioned boolean NOT NULL DEFAULT false, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX feedback_idx_user_id ON feedback (user_id); +-- +-- Table: import_lookups +-- +CREATE TABLE import_lookups ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + name varchar(255) NOT NULL, + entity_id integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_lookups_idx_entity_id ON import_lookups (entity_id); +CREATE INDEX import_lookups_idx_set_id ON import_lookups (set_id); +-- +-- Table: organisation_payroll +-- +CREATE TABLE organisation_payroll ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + submitted_at datetime NOT NULL, + entry_period datetime NOT NULL, + employee_amount integer NOT NULL, + local_employee_amount integer NOT NULL, + gross_payroll numeric(100,0) NOT NULL, + payroll_income_tax numeric(100,0) NOT NULL, + payroll_employee_ni numeric(100,0) NOT NULL, + payroll_employer_ni numeric(100,0) NOT NULL, + payroll_total_pension numeric(100,0) NOT NULL, + payroll_other_benefit numeric(100,0) NOT NULL, + FOREIGN KEY (org_id) REFERENCES organisations(id) +); +CREATE INDEX organisation_payroll_idx_org_id ON organisation_payroll (org_id); +-- +-- Table: session_tokens +-- +CREATE TABLE session_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + token varchar(255) NOT NULL, + user_id integer NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX session_tokens_idx_user_id ON session_tokens (user_id); +CREATE UNIQUE INDEX session_tokens_token ON session_tokens (token); +-- +-- Table: import_values +-- +CREATE TABLE import_values ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + user_name varchar(255) NOT NULL, + purchase_date datetime NOT NULL, + purchase_value varchar(255) NOT NULL, + org_name varchar(255) NOT NULL, + transaction_id integer, + ignore_value boolean NOT NULL DEFAULT false, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_values_idx_set_id ON import_values (set_id); +CREATE INDEX import_values_idx_transaction_id ON import_values (transaction_id); +-- +-- Table: leaderboard_values +-- +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_values_idx_entity_id ON leaderboard_values (entity_id); +CREATE INDEX leaderboard_values_idx_set_id ON leaderboard_values (set_id); +CREATE UNIQUE INDEX leaderboard_values_entity_id_set_id ON leaderboard_values (entity_id, set_id); +COMMIT; diff --git a/share/ddl/SQLite/upgrade/17-18/001-auto.sql b/share/ddl/SQLite/upgrade/17-18/001-auto.sql new file mode 100644 index 0000000..f22ef95 --- /dev/null +++ b/share/ddl/SQLite/upgrade/17-18/001-auto.sql @@ -0,0 +1,12 @@ +-- Convert schema 'share/ddl/_source/deploy/17/001-auto.yml' to 'share/ddl/_source/deploy/18/001-auto.yml':; + +; +BEGIN; + +; +ALTER TABLE entity_association ADD COLUMN esta boolean; + +; + +COMMIT; + diff --git a/share/ddl/_source/deploy/18/001-auto-__VERSION.yml b/share/ddl/_source/deploy/18/001-auto-__VERSION.yml new file mode 100644 index 0000000..907f443 --- /dev/null +++ b/share/ddl/_source/deploy/18/001-auto-__VERSION.yml @@ -0,0 +1,91 @@ +--- +schema: + procedures: {} + tables: + dbix_class_deploymenthandler_versions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - version + match_type: '' + name: dbix_class_deploymenthandler_versions_version + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + ddl: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ddl + order: 3 + size: + - 0 + id: + data_type: int + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + upgrade_sql: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: upgrade_sql + order: 4 + size: + - 0 + version: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: version + order: 2 + size: + - 50 + indices: [] + name: dbix_class_deploymenthandler_versions + options: [] + order: 1 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - __VERSION + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 diff --git a/share/ddl/_source/deploy/18/001-auto.yml b/share/ddl/_source/deploy/18/001-auto.yml new file mode 100644 index 0000000..2dbacb2 --- /dev/null +++ b/share/ddl/_source/deploy/18/001-auto.yml @@ -0,0 +1,1724 @@ +--- +schema: + procedures: {} + tables: + account_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: account_tokens_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 0 + used: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: used + order: 3 + size: + - 0 + indices: [] + name: account_tokens + options: [] + order: 1 + customers: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: customers_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + display_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: display_name + order: 3 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + full_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 4 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 7 + size: + - 5 + - 2 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 8 + size: + - 5 + - 2 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + year_of_birth: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: year_of_birth + order: 5 + size: + - 0 + indices: + - fields: + - entity_id + name: customers_idx_entity_id + options: [] + type: NORMAL + name: customers + options: [] + order: 6 + entities: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: type + order: 2 + size: + - 255 + indices: [] + name: entities + options: [] + order: 2 + entity_association: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entity_association_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + esta: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: esta + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + lis: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: lis + order: 3 + size: + - 0 + indices: + - fields: + - entity_id + name: entity_association_idx_entity_id + options: [] + type: NORMAL + name: entity_association + options: [] + order: 7 + feedback: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: feedback_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + actioned: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: actioned + order: 9 + size: + - 0 + app_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: app_name + order: 5 + size: + - 255 + feedbacktext: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: feedbacktext + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + package_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: package_name + order: 6 + size: + - 255 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + version_code: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_code + order: 7 + size: + - 255 + version_number: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_number + order: 8 + size: + - 255 + indices: + - fields: + - user_id + name: feedback_idx_user_id + options: [] + type: NORMAL + name: feedback + options: [] + order: 12 + gb_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + incode: + data_type: char + default_value: '' + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 3 + size: + - 7 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 4 + size: + - 7 + - 5 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + indices: [] + name: gb_postcodes + options: [] + order: 3 + import_lookups: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: import_lookups_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_lookups_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + indices: + - fields: + - entity_id + name: import_lookups_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: import_lookups_idx_set_id + options: [] + type: NORMAL + name: import_lookups + options: [] + order: 13 + import_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: import_sets + options: [] + order: 4 + import_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: import_values_fk_transaction_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ignore_value: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ignore_value + order: 8 + size: + - 0 + org_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_name + order: 6 + size: + - 255 + purchase_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_date + order: 4 + size: + - 0 + purchase_value: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_value + order: 5 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 7 + size: + - 0 + user_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_name + order: 3 + size: + - 255 + indices: + - fields: + - set_id + name: import_values_idx_set_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: import_values_idx_transaction_id + options: [] + type: NORMAL + name: import_values + options: [] + order: 16 + leaderboard_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - leaderboard_id + match_type: '' + name: leaderboard_sets_fk_leaderboard_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboards + type: FOREIGN KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + leaderboard_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: leaderboard_id + order: 2 + size: + - 0 + indices: + - fields: + - leaderboard_id + name: leaderboard_sets_idx_leaderboard_id + options: [] + type: NORMAL + name: leaderboard_sets + options: [] + order: 8 + leaderboard_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + - set_id + match_type: '' + name: leaderboard_values_entity_id_set_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - entity_id + match_type: '' + name: leaderboard_values_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: leaderboard_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboard_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + position: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: position + order: 4 + size: + - 0 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: set_id + order: 3 + size: + - 0 + trend: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: trend + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 5 + size: + - 100 + - 0 + indices: + - fields: + - entity_id + name: leaderboard_values_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: leaderboard_values_idx_set_id + options: [] + type: NORMAL + name: leaderboard_values + options: [] + order: 17 + leaderboards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - type + match_type: '' + name: leaderboards_type + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 255 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: type + order: 3 + size: + - 255 + indices: [] + name: leaderboards + options: [] + order: 5 + organisation_payroll: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisation_payroll_fk_org_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: employee_amount + order: 5 + size: + - 0 + entry_period: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entry_period + order: 4 + size: + - 0 + gross_payroll: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_payroll + order: 7 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_employee_amount + order: 6 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + payroll_employee_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employee_ni + order: 9 + size: + - 100 + - 0 + payroll_employer_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employer_ni + order: 10 + size: + - 100 + - 0 + payroll_income_tax: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_income_tax + order: 8 + size: + - 100 + - 0 + payroll_other_benefit: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_other_benefit + order: 12 + size: + - 100 + - 0 + payroll_total_pension: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_total_pension + order: 11 + size: + - 100 + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + indices: + - fields: + - org_id + name: organisation_payroll_idx_org_id + options: [] + type: NORMAL + name: organisation_payroll + options: [] + order: 14 + organisations: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: organisations_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + country: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: country + order: 7 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_local: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_local + order: 10 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 12 + size: + - 8 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 13 + size: + - 8 + - 5 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + pending: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: pending + order: 9 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + sector: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: sector + order: 8 + size: + - 1 + street_name: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: street_name + order: 4 + size: + - 0 + submitted_by_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: submitted_by_id + order: 11 + size: + - 0 + town: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: town + order: 5 + size: + - 255 + indices: + - fields: + - entity_id + name: organisations_idx_entity_id + options: [] + type: NORMAL + name: organisations + options: [] + order: 9 + session_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - token + match_type: '' + name: session_tokens_token + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: session_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: token + order: 2 + size: + - 255 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 3 + size: + - 0 + indices: + - fields: + - user_id + name: session_tokens_idx_user_id + options: [] + type: NORMAL + name: session_tokens + options: [] + order: 15 + transactions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transactions_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transactions_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 8 + size: + - 15 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + proof_image: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: proof_image + order: 5 + size: + - 0 + purchase_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_time + order: 7 + size: + - 0 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transactions_idx_buyer_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transactions_idx_seller_id + options: [] + type: NORMAL + name: transactions + options: [] + order: 10 + users: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: users_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: users_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 3 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_admin: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_admin + order: 6 + size: + - 0 + join_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: join_date + order: 4 + size: + - 0 + password: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: password + order: 5 + size: + - 100 + indices: + - fields: + - entity_id + name: users_idx_entity_id + options: [] + type: NORMAL + name: users + options: [] + order: 11 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - AccountToken + - Customer + - Entity + - EntityAssociation + - Feedback + - GbPostcode + - ImportLookup + - ImportSet + - ImportValue + - Leaderboard + - LeaderboardSet + - LeaderboardValue + - Organisation + - OrganisationPayroll + - SessionToken + - Transaction + - User + - ViewQuantisedTransactionPg + - ViewQuantisedTransactionSQLite + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 diff --git a/t/api/v1/supplier/location.t b/t/api/v1/supplier/location.t index 032c716..4e5ff8e 100644 --- a/t/api/v1/supplier/location.t +++ b/t/api/v1/supplier/location.t @@ -59,7 +59,8 @@ $t->post_ok('/api/v1/supplier/location' => json => { longitude => -2.79611, }); - $t->post_ok('/api/v1/supplier/location/lis' => json => { + # Association pin + $t->post_ok('/api/v1/supplier/location/trail' => json => { session_key => $session_key, north_east => { latitude => 54.077665, @@ -69,6 +70,7 @@ $t->post_ok('/api/v1/supplier/location' => json => { latitude => 54.013361, longitude => -2.857647, }, + association => 'lis', }) ->status_is(200)->or($framework->dump_error) ->json_is('/success', Mojo::JSON->true) diff --git a/t/etc/fixtures/config/full.pl b/t/etc/fixtures/config/full.pl index c1959cb..cb28041 100644 --- a/t/etc/fixtures/config/full.pl +++ b/t/etc/fixtures/config/full.pl @@ -124,6 +124,7 @@ }, associations => { lis => 1, + esta => 1, }, type => "organisation", }; From 9ea3125bca13f5775e8b211d7e3f89ee56e2bdba Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 8 Dec 2017 13:30:21 +0000 Subject: [PATCH 037/289] changelog updated --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e8616d..54a0c26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * **Admin Feature** Improved links in relevant places to automatically open in a new tab +* **Admin Feature** Ability to add ESTA to entity Added +* Trail map code updated # v0.9.7 From 2015c15684973789dbb8adb097f993f0233d0294 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Fri, 8 Dec 2017 16:21:31 +0000 Subject: [PATCH 038/289] Updated Changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54a0c26..b3360e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ # Next Release +# v0.10.0 + +* **API Change** Updated API for story trail maps * **Admin Feature** Improved links in relevant places to automatically open in a new tab * **Admin Feature** Ability to add ESTA to entity Added From 7d309755c69d3b2230451b389c4ce82c7b4ac0f4 Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 12 Dec 2017 13:32:52 +0000 Subject: [PATCH 039/289] adding paths and placeholder for customer dash API --- lib/Pear/LocalLoop.pm | 4 + .../LocalLoop/Controller/Api/V1/Customer.pm | 21 ++ .../Controller/Api/V1/Customer/Graphs.pm | 193 ++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 lib/Pear/LocalLoop/Controller/Api/V1/Customer.pm create mode 100644 lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 1e13f09..ac596a0 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -171,6 +171,10 @@ sub startup { $api_v1_org->post('/employee')->to('api-organisation#post_employee_read'); $api_v1_org->post('/employee/add')->to('api-organisation#post_employee_add'); + my $api_v1_cust = $api_v1->under('/customer')->to('api-v1-customer#auth'); + + $api_v1_org->post('/graphs')->to('api-v1-customer-graphs#index'); + my $admin_routes = $r->under('/admin')->to('admin#under'); $admin_routes->get('/home')->to('admin#home'); diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer.pm new file mode 100644 index 0000000..bb5623c --- /dev/null +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer.pm @@ -0,0 +1,21 @@ +package Pear::LocalLoop::Controller::Api::V1::Customer; +use Mojo::Base 'Mojolicious::Controller'; + +sub auth { + my $c = shift; + + return 1 if $c->stash->{api_user}->type eq 'customer'; + + $c->render( + json => { + success => Mojo::JSON->false, + message => 'Not an Customer', + error => 'user_not_cust', + }, + status => 403, + ); + + return 0; +} + +1; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm new file mode 100644 index 0000000..75a98b5 --- /dev/null +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm @@ -0,0 +1,193 @@ +package Pear::LocalLoop::Controller::Api::V1::Customer::Graphs; +use Mojo::Base 'Mojolicious::Controller'; + +has error_messages => sub { + return { + graph => { + required => { message => 'Must request graph type', status => 400 }, + in => { message => 'Unrecognised graph type', status => 400 }, + }, + }; +}; + +sub index { + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->required('graph')->in( qw/ + customers_last_7_days + customers_last_30_days + sales_last_7_days + sales_last_30_days + purchases_last_7_days + purchases_last_30_days + customers_range + / ); + + return $c->api_validation_error if $validation->has_error; + + my $graph_sub = "graph_" . $validation->param('graph'); + + unless ( $c->can($graph_sub) ) { + # Secondary catch in case a mistake has been made + return $c->render( + json => { + success => Mojo::JSON->false, + message => $c->error_messages->{graph}->{in}->{message}, + error => 'in', + }, + status => $c->error_messages->{graph}->{in}->{status}, + ); + } + + return $c->$graph_sub; +} + +sub graph_customers_range { + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->required('start')->is_iso_date; + $validation->required('end')->is_iso_date; + + return $c->api_validation_error if $validation->has_error; + + my $entity = $c->stash->{api_user}->entity; + + my $data = { labels => [], data => [] }; + my $start = $c->parse_iso_date( $validation->param('start') ); + my $end = $c->parse_iso_date( $validation->param('end') ); + + while ( $start <= $end ) { + my $next_end = $start->clone->add( days => 1 ); + my $transactions = $entity->sales + ->search_between( $start, $next_end ) + ->count; + push @{ $data->{ labels } }, $c->format_iso_date( $start ); + push @{ $data->{ data } }, $transactions; + $start->add( days => 1 ); + } + + return $c->render( + json => { + success => Mojo::JSON->true, + graph => $data, + } + ); +} + +sub graph_customers_last_7_days { + my $c = shift; + + my $duration = DateTime::Duration->new( days => 7 ); + return $c->_customers_last_duration( $duration ); +} + +sub graph_customers_last_30_days { + my $c = shift; + + my $duration = DateTime::Duration->new( days => 30 ); + return $c->_customers_last_duration( $duration ); +} + +sub _customers_last_duration { + my ( $c, $duration ) = @_; + + my $entity = $c->stash->{api_user}->entity; + + my $data = { labels => [], data => [] }; + + my ( $start, $end ) = $c->_get_start_end_duration( $duration ); + + while ( $start < $end ) { + my $next_end = $start->clone->add( days => 1 ); + my $transactions = $entity->sales + ->search_between( $start, $next_end ) + ->count; + push @{ $data->{ labels } }, $start->day_name; + push @{ $data->{ data } }, $transactions; + $start->add( days => 1 ); + } + + return $c->render( + json => { + success => Mojo::JSON->true, + graph => $data, + } + ); +} + +sub graph_sales_last_7_days { return shift->_sales_last_duration( 7 ) } +sub graph_sales_last_30_days { return shift->_sales_last_duration( 30 ) } + +sub _sales_last_duration { + my ( $c, $day_duration ) = @_; + + my $duration = DateTime::Duration->new( days => $day_duration ); + my $entity = $c->stash->{api_user}->entity; + + my $data = { labels => [], data => [] }; + + my ( $start, $end ) = $c->_get_start_end_duration( $duration ); + + while ( $start < $end ) { + my $next_end = $start->clone->add( days => 1 ); + my $transactions = $entity->sales + ->search_between( $start, $next_end ) + ->get_column('value') + ->sum || 0 + 0; + push @{ $data->{ labels } }, $start->day_name; + push @{ $data->{ data } }, $transactions / 100000; + $start->add( days => 1 ); + } + + return $c->render( + json => { + success => Mojo::JSON->true, + graph => $data, + } + ); +} + +sub graph_purchases_last_7_days { return shift->_purchases_last_duration( 7 ) } +sub graph_purchases_last_30_days { return shift->_purchases_last_duration( 30 ) } + +sub _purchases_last_duration { + my ( $c, $day_duration ) = @_; + + my $duration = DateTime::Duration->new( days => $day_duration ); + my $entity = $c->stash->{api_user}->entity; + + my $data = { labels => [], data => [] }; + + my ( $start, $end ) = $c->_get_start_end_duration( $duration ); + + while ( $start < $end ) { + my $next_end = $start->clone->add( days => 1 ); + my $transactions = $entity->purchases + ->search_between( $start, $next_end ) + ->get_column('value') + ->sum || 0 + 0; + push @{ $data->{ labels } }, $start->day_name; + push @{ $data->{ data } }, $transactions / 100000; + $start->add( days => 1 ); + } + + return $c->render( + json => { + success => Mojo::JSON->true, + graph => $data, + } + ); +} + +sub _get_start_end_duration { + my ( $c, $duration ) = @_; + my $end = DateTime->today; + my $start = $end->clone->subtract_duration( $duration ); + return ( $start, $end ); +} + +1; From 1057eda445d9769ca0975af9c1d0ed9c49075cda Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 12 Dec 2017 17:21:32 +0000 Subject: [PATCH 040/289] added snippet endpoint and test --- lib/Pear/LocalLoop.pm | 3 +- .../Controller/Api/V1/Customer/Graphs.pm | 15 ++-- .../Controller/Api/V1/Customer/Snippets.pm | 31 ++++++++ t/api/v1/customer/snippets.t | 74 +++++++++++++++++++ 4 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm create mode 100644 t/api/v1/customer/snippets.t diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index ac596a0..f7f4ba4 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -173,7 +173,8 @@ sub startup { my $api_v1_cust = $api_v1->under('/customer')->to('api-v1-customer#auth'); - $api_v1_org->post('/graphs')->to('api-v1-customer-graphs#index'); + $api_v1_cust->post('/graphs')->to('api-v1-customer-graphs#index'); + $api_v1_cust->post('/snippets')->to('api-v1-customer-snippets#index'); my $admin_routes = $r->under('/admin')->to('admin#under'); diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm index 75a98b5..b669dc0 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm @@ -16,13 +16,14 @@ sub index { my $validation = $c->validation; $validation->input( $c->stash->{api_json} ); $validation->required('graph')->in( qw/ - customers_last_7_days - customers_last_30_days - sales_last_7_days - sales_last_30_days - purchases_last_7_days - purchases_last_30_days - customers_range + total_today + avg_spend_today + total_last_week + avg_spend_last_week + total_last_month + avg_spend_last_month + total_user + avg_spend_user / ); return $c->api_validation_error if $validation->has_error; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm new file mode 100644 index 0000000..c1846c9 --- /dev/null +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm @@ -0,0 +1,31 @@ +package Pear::LocalLoop::Controller::Api::V1::Customer::Snippets; +use Mojo::Base 'Mojolicious::Controller'; + +sub index { + my $c = shift; + + my $entity = $c->stash->{api_user}->entity; + my $data = { + user_sum => 0, + user_position => 0, + }; + + my $user_rs = $entity->purchases; + $data->{ user_sum } = $user_rs->get_column('value')->sum || 0; + $data->{ user_sum } /= 100000; + + my $leaderboard_rs = $c->schema->resultset('Leaderboard'); + my $monthly_board = $leaderboard_rs->get_latest( 'monthly_total' ); + my $monthly_values = $monthly_board->values; + $data->{ user_position } = $monthly_values ? $monthly_values->find({ entity_id => $entity->id })->position : 0; + + return $c->render( + json => { + success => Mojo::JSON->true, + snippets => $data, + } + ); + +} + +1; diff --git a/t/api/v1/customer/snippets.t b/t/api/v1/customer/snippets.t new file mode 100644 index 0000000..4a3ae8c --- /dev/null +++ b/t/api/v1/customer/snippets.t @@ -0,0 +1,74 @@ +use Mojo::Base -strict; + +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; + +$t->app->schema->resultset('Leaderboard')->create_new( 'monthly_total', DateTime->now->truncate(to => 'month' )->subtract( months => 1) ); + +my $start = DateTime->today->subtract( hours => 12 ); + +# create 30 days worth of data +for my $count ( 0 .. 60 ) { + my $trans_day = $start->clone->subtract( days => $count ); + + create_random_transaction( 'test1@example.com', $trans_day ); + if ( $count % 2 ) { + create_random_transaction( 'test2@example.com', $trans_day ); + } + if ( $count % 3 ) { + create_random_transaction( 'test3@example.com', $trans_day ); + } + if ( $count % 4 ) { + create_random_transaction( 'test4@example.com', $trans_day ); + } +} + +my $session_key = $framework->login({ + email => 'test1@example.com', + password => 'abc123', +}); + +$t->post_ok('/api/v1/customer/snippets' => json => { + session_key => $session_key, + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/snippets', { + user_sum => 610, + user_position => 1, + }); + +$framework->logout( $session_key ); + +$session_key = $framework->login({ + email => 'test1@example.com', + password => 'abc123', +}); + +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; + $schema->resultset('Transaction')->create({ + buyer => $buyer_result, + seller => $seller_result, + value => 10 * 100000, + proof_image => 'a', + purchase_time => $time, + }); +} + +done_testing; From 5049fa9eedce1f375dcfedc235e6e32f59e97e1f Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 12 Dec 2017 17:23:32 +0000 Subject: [PATCH 041/289] Placeholder test added for graphs --- t/api/v1/customer/graphs.t | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 t/api/v1/customer/graphs.t diff --git a/t/api/v1/customer/graphs.t b/t/api/v1/customer/graphs.t new file mode 100644 index 0000000..6f9a3d9 --- /dev/null +++ b/t/api/v1/customer/graphs.t @@ -0,0 +1,5 @@ +use Mojo::Base -strict; + +use Test::More skip_all => 'Test needs making!'; + +done_testing; From 536ab2155112bc8b0f928dcaf7703c4f2fc3df97 Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 12 Dec 2017 17:31:05 +0000 Subject: [PATCH 042/289] fixed snippets if no values to get --- lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm index c1846c9..139b796 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm @@ -16,9 +16,10 @@ sub index { my $leaderboard_rs = $c->schema->resultset('Leaderboard'); my $monthly_board = $leaderboard_rs->get_latest( 'monthly_total' ); - my $monthly_values = $monthly_board->values; - $data->{ user_position } = $monthly_values ? $monthly_values->find({ entity_id => $entity->id })->position : 0; - + if (defined $monthly_board) { + my $monthly_values = $monthly_board->values; + $data->{ user_position } = $monthly_values ? $monthly_values->find({ entity_id => $entity->id })->position : 0; + } return $c->render( json => { success => Mojo::JSON->true, From 5b745f666bb402fc1de5d170b06be3f4e1d94a66 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 13 Dec 2017 13:33:29 +0000 Subject: [PATCH 043/289] made customer graphs work with passing test --- .../Controller/Api/V1/Customer/Graphs.pm | 126 +++++++++--------- t/api/v1/customer/graphs.t | 79 ++++++++++- 2 files changed, 143 insertions(+), 62 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm index b669dc0..cfd97dd 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm @@ -16,14 +16,10 @@ sub index { my $validation = $c->validation; $validation->input( $c->stash->{api_json} ); $validation->required('graph')->in( qw/ - total_today - avg_spend_today total_last_week avg_spend_last_week total_last_month avg_spend_last_month - total_user - avg_spend_user / ); return $c->api_validation_error if $validation->has_error; @@ -45,6 +41,9 @@ sub index { return $c->$graph_sub; } + +# Replace with code for doughnut +=pod sub graph_customers_range { my $c = shift; @@ -78,22 +77,12 @@ sub graph_customers_range { } ); } +=cut -sub graph_customers_last_7_days { - my $c = shift; - - my $duration = DateTime::Duration->new( days => 7 ); - return $c->_customers_last_duration( $duration ); -} - -sub graph_customers_last_30_days { - my $c = shift; - - my $duration = DateTime::Duration->new( days => 30 ); - return $c->_customers_last_duration( $duration ); -} +sub graph_total_last_week { return shift->_purchases_total_duration( 7 ) } +sub graph_total_last_month { return shift->_purchases_total_duration( 30 ) } -sub _customers_last_duration { +sub _purchases_total_duration { my ( $c, $duration ) = @_; my $entity = $c->stash->{api_user}->entity; @@ -104,11 +93,12 @@ sub _customers_last_duration { while ( $start < $end ) { my $next_end = $start->clone->add( days => 1 ); - my $transactions = $entity->sales + my $transactions = $entity->purchases ->search_between( $start, $next_end ) - ->count; + ->get_column('value') + ->sum || 0 + 0; push @{ $data->{ labels } }, $start->day_name; - push @{ $data->{ data } }, $transactions; + push @{ $data->{ data } }, $transactions / 100000; $start->add( days => 1 ); } @@ -120,10 +110,10 @@ sub _customers_last_duration { ); } -sub graph_sales_last_7_days { return shift->_sales_last_duration( 7 ) } -sub graph_sales_last_30_days { return shift->_sales_last_duration( 30 ) } +sub graph_avg_spend_last_week { return shift->_purchases_avg_spend_duration( 7 ) } +sub graph_avg_spend_last_month { return shift->_purchases_avg_spend_duration( 30 ) } -sub _sales_last_duration { +sub _purchases_avg_spend_duration { my ( $c, $day_duration ) = @_; my $duration = DateTime::Duration->new( days => $day_duration ); @@ -133,47 +123,46 @@ sub _sales_last_duration { my ( $start, $end ) = $c->_get_start_end_duration( $duration ); - while ( $start < $end ) { - my $next_end = $start->clone->add( days => 1 ); - my $transactions = $entity->sales - ->search_between( $start, $next_end ) - ->get_column('value') - ->sum || 0 + 0; - push @{ $data->{ labels } }, $start->day_name; - push @{ $data->{ data } }, $transactions / 100000; - $start->add( days => 1 ); - } - - return $c->render( - json => { - success => Mojo::JSON->true, - graph => $data, + my $dtf = $c->schema->storage->datetime_parser; + my $driver = $c->schema->storage->dbh->{Driver}->{Name}; + my $transaction_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( + { + purchase_time => { + -between => [ + $dtf->format_datetime($start), + $dtf->format_datetime($end), + ], + }, + }, + { + columns => [ + { + quantised => 'quantised_days', + count => \"COUNT(*)", + sum_value => $c->pg_or_sqlite( + 'SUM("me"."value")', + 'SUM("me"."value")', + ), + average_value => $c->pg_or_sqlite( + 'AVG("me"."value")', + 'AVG("me"."value")', + ), + } + ], + group_by => 'quantised_days', + order_by => { '-asc' => 'quantised_days' }, } ); -} - -sub graph_purchases_last_7_days { return shift->_purchases_last_duration( 7 ) } -sub graph_purchases_last_30_days { return shift->_purchases_last_duration( 30 ) } - -sub _purchases_last_duration { - my ( $c, $day_duration ) = @_; - my $duration = DateTime::Duration->new( days => $day_duration ); - my $entity = $c->stash->{api_user}->entity; - - my $data = { labels => [], data => [] }; - - my ( $start, $end ) = $c->_get_start_end_duration( $duration ); +my $data = { + labels => [], + data => [], +}; - while ( $start < $end ) { - my $next_end = $start->clone->add( days => 1 ); - my $transactions = $entity->purchases - ->search_between( $start, $next_end ) - ->get_column('value') - ->sum || 0 + 0; - push @{ $data->{ labels } }, $start->day_name; - push @{ $data->{ data } }, $transactions / 100000; - $start->add( days => 1 ); + for ( $transaction_rs->all ) { + my $quantised = $c->db_datetime_parser->parse_datetime($_->get_column('quantised')); + push @{ $data->{ labels } }, $quantised->day_name; + push @{ $data->{ data } }, ($_->get_column('average_value') || 0) / 100000; } return $c->render( @@ -191,4 +180,19 @@ sub _get_start_end_duration { return ( $start, $end ); } +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; diff --git a/t/api/v1/customer/graphs.t b/t/api/v1/customer/graphs.t index 6f9a3d9..0e20778 100644 --- a/t/api/v1/customer/graphs.t +++ b/t/api/v1/customer/graphs.t @@ -1,5 +1,82 @@ use Mojo::Base -strict; -use Test::More skip_all => 'Test needs making!'; +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; + +my $start = DateTime->today->subtract( hours => 12 ); + +# create 30 days worth of data +for my $count ( 0 .. 29 ) { + 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/v1/customer/graphs' => json => { + session_key => $session_key, + graph => 'avg_spend_last_week', + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/graph', { + labels => [ map { $start->clone->subtract( days => $_ )->day_name } reverse ( 0 .. 6 ) ], + data => [ 10, 10, 10, 10, 10, 10, 10 ], + }); + +$framework->logout( $session_key ); + +$session_key = $framework->login({ + email => 'org@example.com', + password => 'abc123', +}); + +$t->post_ok('/api/v1/customer/graphs' => json => { + session_key => $session_key, + graph => 'avg_spend_last_week', + }) + ->status_is(403) + ->json_is('/success', Mojo::JSON->false) + ->json_is('/error', 'user_not_cust'); + + +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; + $schema->resultset('Transaction')->create({ + buyer => $buyer_result, + seller => $seller_result, + value => 10 * 100000, + proof_image => 'a', + purchase_time => $time, + }); +} done_testing; From 3b191e5c76bce998c448d9bae5169df7804ba33b Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 13 Dec 2017 14:29:17 +0000 Subject: [PATCH 044/289] working graphs on frontend --- .../LocalLoop/Controller/Api/V1/Customer/Graphs.pm | 14 +++++--------- t/api/v1/customer/graphs.t | 4 +++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm index cfd97dd..e8814cd 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm @@ -83,8 +83,9 @@ sub graph_total_last_week { return shift->_purchases_total_duration( 7 ) } sub graph_total_last_month { return shift->_purchases_total_duration( 30 ) } sub _purchases_total_duration { - my ( $c, $duration ) = @_; + my ( $c, $day_duration ) = @_; + my $duration = DateTime::Duration->new( days => $day_duration ); my $entity = $c->stash->{api_user}->entity; my $data = { labels => [], data => [] }; @@ -96,8 +97,8 @@ sub _purchases_total_duration { my $transactions = $entity->purchases ->search_between( $start, $next_end ) ->get_column('value') - ->sum || 0 + 0; - push @{ $data->{ labels } }, $start->day_name; + ->sum || 0 * 1; + push @{ $data->{ labels } }, $c->format_iso_datetime( $start ); push @{ $data->{ data } }, $transactions / 100000; $start->add( days => 1 ); } @@ -154,14 +155,9 @@ sub _purchases_avg_spend_duration { } ); -my $data = { - labels => [], - data => [], -}; - for ( $transaction_rs->all ) { my $quantised = $c->db_datetime_parser->parse_datetime($_->get_column('quantised')); - push @{ $data->{ labels } }, $quantised->day_name; + push @{ $data->{ labels } }, $c->format_iso_datetime( $quantised ); push @{ $data->{ data } }, ($_->get_column('average_value') || 0) / 100000; } diff --git a/t/api/v1/customer/graphs.t b/t/api/v1/customer/graphs.t index 0e20778..da9ec64 100644 --- a/t/api/v1/customer/graphs.t +++ b/t/api/v1/customer/graphs.t @@ -44,7 +44,9 @@ $t->post_ok('/api/v1/customer/graphs' => json => { }) ->status_is(200)->or($framework->dump_error) ->json_is('/graph', { - labels => [ map { $start->clone->subtract( days => $_ )->day_name } reverse ( 0 .. 6 ) ], + labels => [ map { $t->app->format_iso_datetime( + $start->clone->subtract( days => $_ )->subtract( hours => 12 ) + ) } reverse ( 0 .. 6 ) ], data => [ 10, 10, 10, 10, 10, 10, 10 ], }); From a03d3f59773072b547f77b7db0a4902dde3354e7 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 13 Dec 2017 15:29:35 +0000 Subject: [PATCH 045/289] Fixed admin interface for org users --- templates/admin/users/read.html.ep | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/templates/admin/users/read.html.ep b/templates/admin/users/read.html.ep index 7c93f1f..0a63324 100644 --- a/templates/admin/users/read.html.ep +++ b/templates/admin/users/read.html.ep @@ -81,8 +81,10 @@
- - + +
% } else { From 006cc7eb1e162626a73d2897857b7e26fbda7ada Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 14 Dec 2017 17:20:06 +0000 Subject: [PATCH 046/289] fixing graph code and added placeholder pie code --- lib/Pear/LocalLoop.pm | 1 + .../Controller/Api/V1/Customer/Graphs.pm | 48 ++++------------- .../Controller/Api/V1/Organisation/Graphs.pm | 39 ++++++++------ t/api/v1/customer/graphs.t | 54 ++++++++++++++++++- t/api/v1/organisation/graphs.t | 32 +++++++++-- 5 files changed, 114 insertions(+), 60 deletions(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index f7f4ba4..bd5680b 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -175,6 +175,7 @@ sub startup { $api_v1_cust->post('/graphs')->to('api-v1-customer-graphs#index'); $api_v1_cust->post('/snippets')->to('api-v1-customer-snippets#index'); + $api_v1_cust->post('/pies')->to('api-v1-customer-pies#index'); my $admin_routes = $r->under('/admin')->to('admin#under'); diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm index e8814cd..06f45d0 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm @@ -41,44 +41,6 @@ sub index { return $c->$graph_sub; } - -# Replace with code for doughnut -=pod -sub graph_customers_range { - my $c = shift; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - $validation->required('start')->is_iso_date; - $validation->required('end')->is_iso_date; - - return $c->api_validation_error if $validation->has_error; - - my $entity = $c->stash->{api_user}->entity; - - my $data = { labels => [], data => [] }; - my $start = $c->parse_iso_date( $validation->param('start') ); - my $end = $c->parse_iso_date( $validation->param('end') ); - - while ( $start <= $end ) { - my $next_end = $start->clone->add( days => 1 ); - my $transactions = $entity->sales - ->search_between( $start, $next_end ) - ->count; - push @{ $data->{ labels } }, $c->format_iso_date( $start ); - push @{ $data->{ data } }, $transactions; - $start->add( days => 1 ); - } - - return $c->render( - json => { - success => Mojo::JSON->true, - graph => $data, - } - ); -} -=cut - sub graph_total_last_week { return shift->_purchases_total_duration( 7 ) } sub graph_total_last_month { return shift->_purchases_total_duration( 30 ) } @@ -92,6 +54,11 @@ sub _purchases_total_duration { my ( $start, $end ) = $c->_get_start_end_duration( $duration ); + $data->{bounds} = { + min => $c->format_iso_datetime( $start ), + max => $c->format_iso_datetime( $end ), + }; + while ( $start < $end ) { my $next_end = $start->clone->add( days => 1 ); my $transactions = $entity->purchases @@ -124,6 +91,11 @@ sub _purchases_avg_spend_duration { my ( $start, $end ) = $c->_get_start_end_duration( $duration ); + $data->{bounds} = { + min => $c->format_iso_datetime( $start ), + max => $c->format_iso_datetime( $end ), + }; + my $dtf = $c->schema->storage->datetime_parser; my $driver = $c->schema->storage->dbh->{Driver}->{Name}; my $transaction_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm index d1eddaf..5ce5f44 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm @@ -78,35 +78,30 @@ sub graph_customers_range { ); } -sub graph_customers_last_7_days { - my $c = shift; - - my $duration = DateTime::Duration->new( days => 7 ); - return $c->_customers_last_duration( $duration ); -} - -sub graph_customers_last_30_days { - my $c = shift; - - my $duration = DateTime::Duration->new( days => 30 ); - return $c->_customers_last_duration( $duration ); -} +sub graph_customers_last_7_days { return shift->_customers_last_duration( 7 ) } +sub graph_customers_last_30_days { return shift->_customers_last_duration( 30 ) } sub _customers_last_duration { - my ( $c, $duration ) = @_; + my ( $c, $day_duration ) = @_; + my $duration = DateTime::Duration->new( days => $day_duration ); my $entity = $c->stash->{api_user}->entity; my $data = { labels => [], data => [] }; my ( $start, $end ) = $c->_get_start_end_duration( $duration ); + $data->{bounds} = { + min => $c->format_iso_datetime( $start ), + max => $c->format_iso_datetime( $end ), + }; + while ( $start < $end ) { my $next_end = $start->clone->add( days => 1 ); my $transactions = $entity->sales ->search_between( $start, $next_end ) ->count; - push @{ $data->{ labels } }, $start->day_name; + push @{ $data->{ labels } }, $c->format_iso_datetime( $start ); push @{ $data->{ data } }, $transactions; $start->add( days => 1 ); } @@ -132,13 +127,18 @@ sub _sales_last_duration { my ( $start, $end ) = $c->_get_start_end_duration( $duration ); + $data->{bounds} = ( + min => $c->format_iso_datetime( $start ), + max => $c->format_iso_datetime( $end ), + ); + while ( $start < $end ) { my $next_end = $start->clone->add( days => 1 ); my $transactions = $entity->sales ->search_between( $start, $next_end ) ->get_column('value') ->sum || 0 + 0; - push @{ $data->{ labels } }, $start->day_name; + push @{ $data->{ labels } }, $c->format_iso_datetime( $start ); push @{ $data->{ data } }, $transactions / 100000; $start->add( days => 1 ); } @@ -164,13 +164,18 @@ sub _purchases_last_duration { my ( $start, $end ) = $c->_get_start_end_duration( $duration ); + $data->{bounds} = { + min => $c->format_iso_datetime( $start ), + max => $c->format_iso_datetime( $end ), + }; + while ( $start < $end ) { my $next_end = $start->clone->add( days => 1 ); my $transactions = $entity->purchases ->search_between( $start, $next_end ) ->get_column('value') ->sum || 0 + 0; - push @{ $data->{ labels } }, $start->day_name; + push @{ $data->{ labels } }, $c->format_iso_datetime( $start ); push @{ $data->{ data } }, $transactions / 100000; $start->add( days => 1 ); } diff --git a/t/api/v1/customer/graphs.t b/t/api/v1/customer/graphs.t index da9ec64..580578c 100644 --- a/t/api/v1/customer/graphs.t +++ b/t/api/v1/customer/graphs.t @@ -40,16 +40,68 @@ my $session_key = $framework->login({ $t->post_ok('/api/v1/customer/graphs' => json => { session_key => $session_key, - graph => 'avg_spend_last_week', + graph => 'total_last_week', }) ->status_is(200)->or($framework->dump_error) ->json_is('/graph', { labels => [ map { $t->app->format_iso_datetime( $start->clone->subtract( days => $_ )->subtract( hours => 12 ) ) } reverse ( 0 .. 6 ) ], + bounds => { + min => $t->app->format_iso_datetime($start->clone->subtract( days => 6 )->subtract( hours => 12 ) ), + max => $t->app->format_iso_datetime($start->clone->add( hours => 12 )), + }, + data => [ 20, 40, 20, 30, 30, 40, 10 ], + }); + +$t->post_ok('/api/v1/customer/graphs' => json => { + session_key => $session_key, + graph => 'avg_spend_last_week', + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/graph', { + labels => [ map { $t->app->format_iso_datetime( + $start->clone->subtract( days => $_ )->subtract( hours => 12 ) + ) } reverse ( 0 .. 29 ) ], + bounds => { + min => $t->app->format_iso_datetime($start->clone->subtract( days => 6 )->subtract( hours => 12 ) ), + max => $t->app->format_iso_datetime($start->clone->add( hours => 12 )), + }, data => [ 10, 10, 10, 10, 10, 10, 10 ], }); +$t->post_ok('/api/v1/customer/graphs' => json => { + session_key => $session_key, + graph => 'total_last_month', + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/graph', { + labels => [ map { $t->app->format_iso_datetime( + $start->clone->subtract( days => $_ )->subtract( hours => 12 ) + ) } reverse ( 0 .. 29 ) ], + bounds => { + min => $t->app->format_iso_datetime($start->clone->subtract( days => 29 )->subtract( hours => 12 ) ), + max => $t->app->format_iso_datetime($start->clone->add( hours => 12 )), + }, + data => [ 40, 20, 30, 30, 40, 10, 40, 30, 30, 20, 40, 20, 40, 20, 30, 30, 40, 10, 40, 30, 30, 20, 40, 20, 40, 20, 30, 30, 40, 10 ], + }); + +$t->post_ok('/api/v1/customer/graphs' => json => { + session_key => $session_key, + graph => 'avg_spend_last_month', + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/graph', { + labels => [ map { $t->app->format_iso_datetime( + $start->clone->subtract( days => $_ )->subtract( hours => 12 ) + ) } reverse ( 0 .. 29 ) ], + bounds => { + min => $t->app->format_iso_datetime($start->clone->subtract( days => 29 )->subtract( hours => 12 ) ), + max => $t->app->format_iso_datetime($start->clone->add( hours => 12 )), + }, + data => [ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ], + }); + $framework->logout( $session_key ); $session_key = $framework->login({ diff --git a/t/api/v1/organisation/graphs.t b/t/api/v1/organisation/graphs.t index 57b6cbb..5fd0da7 100644 --- a/t/api/v1/organisation/graphs.t +++ b/t/api/v1/organisation/graphs.t @@ -44,7 +44,13 @@ $t->post_ok('/api/v1/organisation/graphs' => json => { }) ->status_is(200)->or($framework->dump_error) ->json_is('/graph', { - labels => [ map { $start->clone->subtract( days => $_ )->day_name } reverse ( 0 .. 6 ) ], + labels => [ map { $t->app->format_iso_datetime( + $start->clone->subtract( days => $_ )->subtract( hours => 12 ) + ) } reverse ( 0 .. 6 ) ], + bounds => { + min => $t->app->format_iso_datetime($start->clone->subtract( days => 6 )->subtract( hours => 12 ) ), + max => $t->app->format_iso_datetime($start->clone->add( hours => 12 )), + }, data => [ 2, 4, 2, 3, 3, 4, 1 ], }); @@ -54,7 +60,13 @@ $t->post_ok('/api/v1/organisation/graphs' => json => { }) ->status_is(200)->or($framework->dump_error) ->json_is('/graph', { - labels => [ map { $start->clone->subtract( days => $_ )->day_name } reverse ( 0 .. 29 ) ], + labels => [ map { $t->app->format_iso_datetime( + $start->clone->subtract( days => $_ )->subtract( hours => 12 ) + ) } reverse ( 0 .. 29 ) ], + bounds => { + min => $t->app->format_iso_datetime($start->clone->subtract( days => 6 )->subtract( hours => 12 ) ), + max => $t->app->format_iso_datetime($start->clone->add( hours => 12 )), + }, data => [ 4, 2, 3, 3, 4, 1, 4, 3, 3, 2, 4, 2, 4, 2, 3, 3, 4, 1, 4, 3, 3, 2, 4, 2, 4, 2, 3, 3, 4, 1 ], }); @@ -64,7 +76,13 @@ $t->post_ok('/api/v1/organisation/graphs' => json => { }) ->status_is(200)->or($framework->dump_error) ->json_is('/graph', { - labels => [ map { $start->clone->subtract( days => $_ )->day_name } reverse ( 0 .. 6 ) ], + labels => [ map { $t->app->format_iso_datetime( + $start->clone->subtract( days => $_ )->subtract( hours => 12 ) + ) } reverse ( 0 .. 6 ) ], + bounds => { + min => $t->app->format_iso_datetime($start->clone->subtract( days => 6 )->subtract( hours => 12 ) ), + max => $t->app->format_iso_datetime($start->clone->add( hours => 12 )), + }, data => [ 20, 40, 20, 30, 30, 40, 10 ], }); @@ -74,7 +92,13 @@ $t->post_ok('/api/v1/organisation/graphs' => json => { }) ->status_is(200)->or($framework->dump_error) ->json_is('/graph', { - labels => [ map { $start->clone->subtract( days => $_ )->day_name } reverse ( 0 .. 29 ) ], + labels => [ map { $t->app->format_iso_datetime( + $start->clone->subtract( days => $_ )->subtract( hours => 12 ) + ) } reverse ( 0 .. 29 ) ], + bounds => { + min => $t->app->format_iso_datetime($start->clone->subtract( days => 6 )->subtract( hours => 12 ) ), + max => $t->app->format_iso_datetime($start->clone->add( hours => 12 )), + }, data => [ 40, 20, 30, 30, 40, 10, 40, 30, 30, 20, 40, 20, 40, 20, 30, 30, 40, 10, 40, 30, 30, 20, 40, 20, 40, 20, 30, 30, 40, 10 ], }); From 9594f9f7469154dbc0667acfef7f561e0df5b6ea Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 14 Dec 2017 17:22:09 +0000 Subject: [PATCH 047/289] widget graph test fixed --- t/api/v1/customer/graphs.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/api/v1/customer/graphs.t b/t/api/v1/customer/graphs.t index 580578c..a2e6010 100644 --- a/t/api/v1/customer/graphs.t +++ b/t/api/v1/customer/graphs.t @@ -62,7 +62,7 @@ $t->post_ok('/api/v1/customer/graphs' => json => { ->json_is('/graph', { labels => [ map { $t->app->format_iso_datetime( $start->clone->subtract( days => $_ )->subtract( hours => 12 ) - ) } reverse ( 0 .. 29 ) ], + ) } reverse ( 0 .. 6 ) ], bounds => { min => $t->app->format_iso_datetime($start->clone->subtract( days => 6 )->subtract( hours => 12 ) ), max => $t->app->format_iso_datetime($start->clone->add( hours => 12 )), From 12bd6b3ec961052e478df1441f3e076bf20684ab Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 14 Dec 2017 17:25:00 +0000 Subject: [PATCH 048/289] org graphs and relevant test fixed --- lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm | 4 ++-- t/api/v1/organisation/graphs.t | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm index 5ce5f44..a6f56eb 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm @@ -127,10 +127,10 @@ sub _sales_last_duration { my ( $start, $end ) = $c->_get_start_end_duration( $duration ); - $data->{bounds} = ( + $data->{bounds} = { min => $c->format_iso_datetime( $start ), max => $c->format_iso_datetime( $end ), - ); + }; while ( $start < $end ) { my $next_end = $start->clone->add( days => 1 ); diff --git a/t/api/v1/organisation/graphs.t b/t/api/v1/organisation/graphs.t index 5fd0da7..3e438b4 100644 --- a/t/api/v1/organisation/graphs.t +++ b/t/api/v1/organisation/graphs.t @@ -64,7 +64,7 @@ $t->post_ok('/api/v1/organisation/graphs' => json => { $start->clone->subtract( days => $_ )->subtract( hours => 12 ) ) } reverse ( 0 .. 29 ) ], bounds => { - min => $t->app->format_iso_datetime($start->clone->subtract( days => 6 )->subtract( hours => 12 ) ), + min => $t->app->format_iso_datetime($start->clone->subtract( days => 29 )->subtract( hours => 12 ) ), max => $t->app->format_iso_datetime($start->clone->add( hours => 12 )), }, data => [ 4, 2, 3, 3, 4, 1, 4, 3, 3, 2, 4, 2, 4, 2, 3, 3, 4, 1, 4, 3, 3, 2, 4, 2, 4, 2, 3, 3, 4, 1 ], @@ -96,7 +96,7 @@ $t->post_ok('/api/v1/organisation/graphs' => json => { $start->clone->subtract( days => $_ )->subtract( hours => 12 ) ) } reverse ( 0 .. 29 ) ], bounds => { - min => $t->app->format_iso_datetime($start->clone->subtract( days => 6 )->subtract( hours => 12 ) ), + min => $t->app->format_iso_datetime($start->clone->subtract( days => 29 )->subtract( hours => 12 ) ), max => $t->app->format_iso_datetime($start->clone->add( hours => 12 )), }, data => [ 40, 20, 30, 30, 40, 10, 40, 30, 30, 20, 40, 20, 40, 20, 30, 30, 40, 10, 40, 30, 30, 20, 40, 20, 40, 20, 30, 30, 40, 10 ], From cb39b419d6fcc7b9df763ed1f9af3900e4499d27 Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 14 Dec 2017 20:30:44 +0000 Subject: [PATCH 049/289] Added new stats and fixed test --- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 62 +++++----- .../Controller/Api/V1/Customer/Pies.pm | 28 +++++ .../Result/ViewQuantisedTransactionPg.pm | 3 +- .../Result/ViewQuantisedTransactionSQLite.pm | 3 +- t/api/stats.t | 113 +++++------------- 5 files changed, 95 insertions(+), 114 deletions(-) create mode 100644 lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index ad984e2..d626c46 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -17,44 +17,42 @@ sub post_index { my $user = $c->stash->{api_user}->entity; - my $today_rs = $user->purchases->today_rs; - my $today_sum = $today_rs->get_column('value')->sum || 0; - my $today_count = $today_rs->count; + my $duration = DateTime::Duration->new( weeks => 7 ); + my $end = DateTime->today; + my $start = $end->clone->subtract_duration( $duration ); - my $week_rs = $user->purchases->week_rs; - my $week_sum = $week_rs->get_column('value')->sum || 0; - my $week_count = $week_rs->count; + my $data = { purchases => [] }; - my $month_rs = $user->purchases->month_rs; - my $month_sum = $month_rs->get_column('value')->sum || 0; - my $month_count = $month_rs->count; - - my $user_rs = $user->purchases; - my $user_sum = $user_rs->get_column('value')->sum || 0; - my $user_count = $user_rs->count; - - my $global_rs = $c->schema->resultset('Transaction'); - my $global_sum = $global_rs->get_column('value')->sum || 0; - my $global_count = $global_rs->count; + my $dtf = $c->schema->storage->datetime_parser; + my $driver = $c->schema->storage->dbh->{Driver}->{Name}; + my $transaction_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( + { + purchase_time => { + -between => [ + $dtf->format_datetime($start), + $dtf->format_datetime($end), + ], + }, + }, + { + columns => [ + { + quantised => 'quantised_weeks', + count => \"COUNT(*)", + } + ], + group_by => 'quantised_weeks', + order_by => { '-asc' => 'quantised_weeks' }, + } + ); - my $leaderboard_rs = $c->schema->resultset('Leaderboard'); - my $monthly_board = $leaderboard_rs->get_latest( 'monthly_total' ); - my $monthly_values = $monthly_board->values; - my $current_user_position = $monthly_values ? $monthly_values->find({ entity_id => $user->id }) : undef; + for ( $transaction_rs->all ) { + push @{ $data->{ purchases } }, ($_->get_column('count') || 0); + } return $c->render( json => { success => Mojo::JSON->true, - today_sum => $today_sum / 100000, - today_count => $today_count, - week_sum => $week_sum / 100000, - week_count => $week_count, - month_sum => $month_sum / 100000, - month_count => $month_count, - user_sum => $user_sum / 100000, - user_count => $user_count, - global_sum => $global_sum / 100000, - global_count => $global_count, - user_position => defined $current_user_position ? $current_user_position->position : 0, + data => $data, }); } diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm new file mode 100644 index 0000000..ae0340b --- /dev/null +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm @@ -0,0 +1,28 @@ +package Pear::LocalLoop::Controller::Api::V1::Customer::Pies; +use Mojo::Base 'Mojolicious::Controller'; + +sub index { + my $c = shift; + + my $entity = $c->stash->{api_user}->entity; + my $data = { data => [] }; + + my $data = { + 'Local shop local purchaser' => 20, + 'Local shop non-local purchaser' => 20, + 'Non-local shop local purchaser' => 20, + 'Non-local shop non-local purchaser' => 20, + }; + + #TODO insert code fetching numbers here + + return $c->render( + json => { + success => Mojo::JSON->true, + pie => $data, + } + ); + +} + +1; diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm index fabbd38..68513ac 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm @@ -14,7 +14,8 @@ SELECT "value", "distance", "purchase_time", DATE_TRUNC('hour', "purchase_time") AS "quantised_hours", - DATE_TRUNC('day', "purchase_time") AS "quantised_days" + DATE_TRUNC('day', "purchase_time") AS "quantised_days", + DATE_TRUNC('week', "purchase_time") AS "quantised_weeks" FROM "transactions" /); diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm index 2ce3aac..649d6cd 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm @@ -14,7 +14,8 @@ SELECT "value", "distance", "purchase_time", 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")) AS "quantised_days", + DATETIME(STRFTIME('%Y-%m-%d 00:00:00',"purchase_time", 'weekday 1')) AS "quantised_weeks" FROM "transactions" /); diff --git a/t/api/stats.t b/t/api/stats.t index 0484664..11a0a93 100644 --- a/t/api/stats.t +++ b/t/api/stats.t @@ -14,98 +14,51 @@ $framework->install_fixtures('users'); my $t = $framework->framework; my $schema = $t->app->schema; -my $dtf = $schema->storage->datetime_parser; -my $org_result = $schema->resultset('Organisation')->find({ name => 'Test Org' })->entity; -my $user_result = $schema->resultset('User')->find({ email => 'test1@example.com' })->entity; +my $start = DateTime->today->subtract( hours => 12 ); + +# create 40 days worth of data +for my $count ( 0 .. 40 ) { + 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', + email => 'test1@example.com', password => 'abc123', }); -$t->app->schema->resultset('Leaderboard')->create_new( 'monthly_total', DateTime->now->truncate(to => 'month' )->subtract( months => 1) ); - -$t->post_ok('/api/stats' => json => { session_key => $session_key } ) +$t->post_ok('/api/stats' => json => { + session_key => $session_key, + }) ->status_is(200)->or($framework->dump_error) - ->json_is('/success', Mojo::JSON->true) - ->json_is('/today_sum', 0) - ->json_is('/today_count', 0) - ->json_is('/week_sum', 0) - ->json_is('/week_count', 0) - ->json_is('/month_sum', 0) - ->json_is('/month_count', 0) - ->json_is('/user_sum', 0) - ->json_is('/user_count', 0) - ->json_is('/global_sum', 0) - ->json_is('/global_count', 0); - -for ( 1 .. 10 ) { - $user_result->create_related( 'purchases', { - seller_id => $org_result->id, - value => $_ * 100000, - proof_image => 'a', - }); -} - -for ( 11 .. 20 ) { - $user_result->create_related( 'purchases', { - seller_id => $org_result->id, - value => $_ * 100000, - proof_image => 'a', - purchase_time => $dtf->format_datetime(DateTime->today()->subtract( days => 5 )), - }); -} - -for ( 21 .. 30 ) { - $user_result->create_related( 'purchases', { - seller_id => $org_result->id, - value => $_ * 100000, - proof_image => 'a', - purchase_time => $dtf->format_datetime(DateTime->today()->subtract( days => 25 )), + ->json_is('/data', { + purchases => [ 12, 19, 21, 20, 21, 20, 5 ], }); -} -for ( 31 .. 40 ) { - $user_result->create_related( 'purchases', { - seller_id => $org_result->id, - value => $_ * 100000, - proof_image => 'a', - purchase_time => $dtf->format_datetime(DateTime->today()->subtract( days => 50 )), - }); -} +sub create_random_transaction { + my $buyer = shift; + my $time = shift; -for ( 41 .. 50 ) { - $org_result->create_related( 'purchases', { - seller_id => $org_result->id, - value => $_ * 100000, + my $buyer_result = $schema->resultset('User')->find({ email => $buyer })->entity; + my $seller_result = $schema->resultset('Organisation')->find({ name => 'Test Org' })->entity; + $schema->resultset('Transaction')->create({ + buyer => $buyer_result, + seller => $seller_result, + value => 10 * 100000, proof_image => 'a', - purchase_time => $dtf->format_datetime(DateTime->today()->subtract( days => 50 )), + purchase_time => $time, }); } -is $user_result->purchases->search({ - purchase_time => { - -between => [ - $dtf->format_datetime(DateTime->today()), - $dtf->format_datetime(DateTime->today()->add( days => 1 )), - ], - }, -})->get_column('value')->sum, 5500000, 'Got correct sum'; -is $user_result->purchases->today_rs->get_column('value')->sum, 5500000, 'Got correct sum through rs'; - -$t->post_ok('/api/stats' => json => { session_key => $session_key } ) - ->status_is(200) - ->json_is('/success', Mojo::JSON->true) - ->json_is('/today_sum', 55) - ->json_is('/today_count', 10) - ->json_is('/week_sum', 155) - ->json_is('/week_count', 10) - ->json_is('/month_sum', 410) - ->json_is('/month_count', 20) - ->json_is('/user_sum', 820) - ->json_is('/user_count', 40) - ->json_is('/global_sum', 1275) - ->json_is('/global_count', 50); - done_testing; From 7ffdfc5bd34b1d6a5f6a1fcea1df03279cc21b72 Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 15 Dec 2017 14:59:38 +0000 Subject: [PATCH 050/289] pie code made functional and relevant distance code updated --- lib/Pear/LocalLoop/Controller/Admin/Users.pm | 7 +++ lib/Pear/LocalLoop/Controller/Api/Stats.pm | 8 +-- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 6 +++ .../Controller/Api/V1/Customer/Pies.pm | 50 ++++++++++++++++--- 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Users.pm b/lib/Pear/LocalLoop/Controller/Admin/Users.pm index e731d7b..a1d4aef 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Users.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Users.pm @@ -92,6 +92,11 @@ sub update { return $c->redirect_to( '/admin/users/' . $id ); } + my $location = $c->get_location_from_postcode( + $validation->param('postcode'), + $user->type, + ); + if ( $user->type eq 'customer' ){ try { @@ -100,6 +105,7 @@ sub update { full_name => $validation->param('full_name'), display_name => $validation->param('display_name'), postcode => $validation->param('postcode'), + ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), }); $user->update({ email => $validation->param('email'), @@ -125,6 +131,7 @@ sub update { town => $validation->param('town'), sector => $validation->param('sector'), postcode => $validation->param('postcode'), + ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), }); $user->update({ email => $validation->param('email'), diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index d626c46..af36a67 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -21,7 +21,8 @@ sub post_index { my $end = DateTime->today; my $start = $end->clone->subtract_duration( $duration ); - my $data = { purchases => [] }; + my $weeks = { purchases => [] }; + my $sectors = { sectors => [], purchases => [] }; my $dtf = $c->schema->storage->datetime_parser; my $driver = $c->schema->storage->dbh->{Driver}->{Name}; @@ -47,12 +48,13 @@ sub post_index { ); for ( $transaction_rs->all ) { - push @{ $data->{ purchases } }, ($_->get_column('count') || 0); + push @{ $weeks->{ purchases } }, ($_->get_column('count') || 0); } return $c->render( json => { success => Mojo::JSON->true, - data => $data, + weeks => $weeks, + sectors => $sectors, }); } diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index 15fa500..3783d7f 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -146,12 +146,18 @@ sub post_upload { return $c->api_validation_error if $validation->has_error; + my $location = $c->get_location_from_postcode( + $validation->param('postcode'), + 'organisation', + ); + my $entity = $c->schema->resultset('Entity')->create_org({ submitted_by_id => $user->id, name => $validation->param('organisation_name'), street_name => $validation->param('street_name'), town => $validation->param('town'), postcode => $validation->param('postcode'), + ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), pending => 1, }); $organisation = $entity->organisation; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm index ae0340b..06c57b1 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm @@ -5,17 +5,51 @@ sub index { my $c = shift; my $entity = $c->stash->{api_user}->entity; - my $data = { data => [] }; - my $data = { - 'Local shop local purchaser' => 20, - 'Local shop non-local purchaser' => 20, - 'Non-local shop local purchaser' => 20, - 'Non-local shop non-local purchaser' => 20, - }; + my $purchase_rs = $entity->purchases; + my $local_org_local_purchase = $purchase_rs->search({ + "me.distance" => { '<', 20000 }, + 'organisation.is_local' => 1, + }, + { + join => { 'seller' => 'organisation' }, + } + ); + + my $local_org_non_local_purchase = $purchase_rs->search({ + "me.distance" => { '>=', 20000 }, + 'organisation.is_local' => 1, + }, + { + join => { 'seller' => 'organisation' }, + } + ); - #TODO insert code fetching numbers here + my $non_local_org_local_purchase = $purchase_rs->search({ + "me.distance" => { '<', 20000 }, + 'organisation.is_local' => 0, + }, + { + join => { 'seller' => 'organisation' }, + } + ); + + my $non_local_org_non_local_purchase = $purchase_rs->search({ + "me.distance" => { '>=', 20000 }, + 'organisation.is_local' => 0, + }, + { + join => { 'seller' => 'organisation' }, + } + ); + 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, + }; + return $c->render( json => { success => Mojo::JSON->true, From 8c811d52bf9768c440f1df77d50b8ee82006d258 Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 15 Dec 2017 15:05:04 +0000 Subject: [PATCH 051/289] fixed stats test --- t/api/stats.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/api/stats.t b/t/api/stats.t index 11a0a93..9ef6397 100644 --- a/t/api/stats.t +++ b/t/api/stats.t @@ -42,8 +42,8 @@ $t->post_ok('/api/stats' => json => { session_key => $session_key, }) ->status_is(200)->or($framework->dump_error) - ->json_is('/data', { - purchases => [ 12, 19, 21, 20, 21, 20, 5 ], + ->json_is('/weeks', { + purchases => [ 8, 21, 19, 22, 20, 20, 8 ], }); sub create_random_transaction { From 2012e672733107af33c7a5923e011fc751cdc7f4 Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 15 Dec 2017 15:30:47 +0000 Subject: [PATCH 052/289] sectors code added --- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 24 ++++++++++++++++--- .../Controller/Api/V1/Customer/Graphs.pm | 1 + .../Result/ViewQuantisedTransactionPg.pm | 2 ++ .../Result/ViewQuantisedTransactionSQLite.pm | 2 ++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index af36a67..4e9b4ff 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -15,7 +15,7 @@ has error_messages => sub { sub post_index { my $c = shift; - my $user = $c->stash->{api_user}->entity; + my $entity = $c->stash->{api_user}->entity; my $duration = DateTime::Duration->new( weeks => 7 ); my $end = DateTime->today; @@ -26,7 +26,7 @@ sub post_index { my $dtf = $c->schema->storage->datetime_parser; my $driver = $c->schema->storage->dbh->{Driver}->{Name}; - my $transaction_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( + my $week_transaction_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( { purchase_time => { -between => [ @@ -34,6 +34,7 @@ sub post_index { $dtf->format_datetime($end), ], }, + buyer_id => $entity->id, }, { columns => [ @@ -47,10 +48,27 @@ sub post_index { } ); - for ( $transaction_rs->all ) { + for ( $week_transaction_rs->all ) { push @{ $weeks->{ purchases } }, ($_->get_column('count') || 0); } + my $sector_purchase_rs = $entity->purchases->search({}, + { + join => { 'seller' => 'organisation' }, + columns => { + sector => "organisation.sector", + count => \"COUNT(*)", + }, + group_by => "organisation.sector", + order_by => { '-desc' => "COUNT(*)" }, + } + ); + + for ( $sector_purchase_rs->all ) { + push @{ $sectors->{ sectors } }, $_->get_column('sector'); + push @{ $sectors->{ purchases } }, ($_->get_column('count') || 0); + } + return $c->render( json => { success => Mojo::JSON->true, weeks => $weeks, diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm index 06f45d0..f48e52b 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm @@ -106,6 +106,7 @@ sub _purchases_avg_spend_duration { $dtf->format_datetime($end), ], }, + buyer_id => $entity->id, }, { columns => [ diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm index 68513ac..91ceede 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm @@ -13,6 +13,8 @@ __PACKAGE__->result_source_instance->view_definition( qq/ SELECT "value", "distance", "purchase_time", + "buyer_id", + "seller_id", DATE_TRUNC('hour', "purchase_time") AS "quantised_hours", DATE_TRUNC('day', "purchase_time") AS "quantised_days", DATE_TRUNC('week', "purchase_time") AS "quantised_weeks" diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm index 649d6cd..abf95dd 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm @@ -13,6 +13,8 @@ __PACKAGE__->result_source_instance->view_definition( qq/ SELECT "value", "distance", "purchase_time", + "buyer_id", + "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" From 9edf15b95b479817199d9ee930ec8527f8024e5f Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 15 Dec 2017 17:09:15 +0000 Subject: [PATCH 053/289] pie test added --- t/api/v1/customer/pies.t | 67 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 t/api/v1/customer/pies.t diff --git a/t/api/v1/customer/pies.t b/t/api/v1/customer/pies.t new file mode 100644 index 0000000..53fdd8f --- /dev/null +++ b/t/api/v1/customer/pies.t @@ -0,0 +1,67 @@ +use Mojo::Base -strict; + +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; + +my $start = DateTime->today->subtract( hours => 12 ); + +# create 30 days worth of data +for my $count ( 0 .. 29 ) { + 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/v1/customer/pies' => json => { + session_key => $session_key, + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/pie', { + 'Local shop local purchaser' => 0, + 'Local shop non-local purchaser' => 0, + 'Non-local shop local purchaser' => 0, + 'Non-local shop non-local purchaser' => 0, + }); + +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; + $schema->resultset('Transaction')->create({ + buyer => $buyer_result, + seller => $seller_result, + value => 10 * 100000, + proof_image => 'a', + purchase_time => $time, + }); +} + +done_testing; From 7d044addeb344749c7a0d185aaa8f4cba24f570a Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 15 Dec 2017 17:52:02 +0000 Subject: [PATCH 054/289] tests fixed --- t/api/stats.t | 6 ++++++ t/etc/fixtures/config/users.pl | 2 +- t/etc/fixtures/data/users/organisations/1.fix | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/t/api/stats.t b/t/api/stats.t index 9ef6397..cad04ff 100644 --- a/t/api/stats.t +++ b/t/api/stats.t @@ -38,12 +38,18 @@ my $session_key = $framework->login({ password => 'abc123', }); +#TODO be able to define start and end below in request + $t->post_ok('/api/stats' => json => { session_key => $session_key, }) ->status_is(200)->or($framework->dump_error) ->json_is('/weeks', { purchases => [ 8, 21, 19, 22, 20, 20, 8 ], + }) + ->json_is('/sectors', { + sectors => ['A'], + purchases => [118], }); sub create_random_transaction { diff --git a/t/etc/fixtures/config/users.pl b/t/etc/fixtures/config/users.pl index 9a7f5ca..0341077 100644 --- a/t/etc/fixtures/config/users.pl +++ b/t/etc/fixtures/config/users.pl @@ -91,6 +91,7 @@ street_name => 'Test Street', town => 'Lancaster', postcode => 'LA1 1AA', + sector => 'A', }, user => { email => 'org@example.com', @@ -124,4 +125,3 @@ schema => $schema, directory => "$Bin/../data/" . $data_set, }); - diff --git a/t/etc/fixtures/data/users/organisations/1.fix b/t/etc/fixtures/data/users/organisations/1.fix index b761450..72165ed 100644 --- a/t/etc/fixtures/data/users/organisations/1.fix +++ b/t/etc/fixtures/data/users/organisations/1.fix @@ -7,7 +7,7 @@ $HASH1 = { pending => 0, postcode => 'LA1 1AA', - sector => undef, + sector => 'A', street_name => 'Test Street', submitted_by_id From 767ed7323447e57048897206cde9344e65777b8d Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 15 Dec 2017 17:56:39 +0000 Subject: [PATCH 055/289] changelog updated --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54a0c26..1c15ebd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ a new tab * **Admin Feature** Ability to add ESTA to entity Added * Trail map code updated +* Added API for customer graphs +* Revamped graphs code +* Added API for customer local purchase pie charts +* Added API for customer snippets +* Added API for sector purchase list for customer dashboard +* **Admin Feature** Fixed org sector on user edit layout and text # v0.9.7 From e6ce9cc81a9f2a8223cf43a603f4351ce0f37de9 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Dec 2017 12:56:45 +0000 Subject: [PATCH 056/289] added support for mobile app back --- lib/Pear/LocalLoop.pm | 1 + lib/Pear/LocalLoop/Controller/Api/Stats.pm | 46 ++++++++++++++++++++++ t/api/stats.t | 2 +- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index bd5680b..6ab7fa8 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -148,6 +148,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/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'); $api->post('/outgoing-transactions')->to('api-transactions#post_transaction_list_purchases'); diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index 4e9b4ff..e2b98e2 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -15,6 +15,52 @@ has error_messages => sub { sub post_index { my $c = shift; + my $user = $c->stash->{api_user}->entity; + + my $today_rs = $user->purchases->today_rs; + my $today_sum = $today_rs->get_column('value')->sum || 0; + my $today_count = $today_rs->count; + + my $week_rs = $user->purchases->week_rs; + my $week_sum = $week_rs->get_column('value')->sum || 0; + my $week_count = $week_rs->count; + + my $month_rs = $user->purchases->month_rs; + my $month_sum = $month_rs->get_column('value')->sum || 0; + my $month_count = $month_rs->count; + + my $user_rs = $user->purchases; + my $user_sum = $user_rs->get_column('value')->sum || 0; + my $user_count = $user_rs->count; + + my $global_rs = $c->schema->resultset('Transaction'); + my $global_sum = $global_rs->get_column('value')->sum || 0; + my $global_count = $global_rs->count; + + my $leaderboard_rs = $c->schema->resultset('Leaderboard'); + my $monthly_board = $leaderboard_rs->get_latest( 'monthly_total' ); + my $monthly_values = $monthly_board->values; + my $current_user_position = $monthly_values ? $monthly_values->find({ entity_id => $user->id }) : undef; + + return $c->render( json => { + success => Mojo::JSON->true, + today_sum => $today_sum / 100000, + today_count => $today_count, + week_sum => $week_sum / 100000, + week_count => $week_count, + month_sum => $month_sum / 100000, + month_count => $month_count, + user_sum => $user_sum / 100000, + user_count => $user_count, + global_sum => $global_sum / 100000, + global_count => $global_count, + user_position => defined $current_user_position ? $current_user_position->position : 0, + }); +} + +sub post_customer { + my $c = shift; + my $entity = $c->stash->{api_user}->entity; my $duration = DateTime::Duration->new( weeks => 7 ); diff --git a/t/api/stats.t b/t/api/stats.t index cad04ff..620f5d3 100644 --- a/t/api/stats.t +++ b/t/api/stats.t @@ -40,7 +40,7 @@ my $session_key = $framework->login({ #TODO be able to define start and end below in request -$t->post_ok('/api/stats' => json => { +$t->post_ok('/api/stats/customer' => json => { session_key => $session_key, }) ->status_is(200)->or($framework->dump_error) From 6f085ff54122d1fd6413f4b4d368a5caaa8ba2a8 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Dec 2017 14:05:51 +0000 Subject: [PATCH 057/289] Fixed stats test --- cpanfile | 7 +++++-- t/api/stats.t | 8 +++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cpanfile b/cpanfile index 1916f82..5ef4b1f 100644 --- a/cpanfile +++ b/cpanfile @@ -6,7 +6,6 @@ requires 'Mojo::JSON'; requires 'Email::Valid'; requires 'Geo::UK::Postcode::Regex' => '0.017'; requires 'Authen::Passphrase::BlowfishCrypt'; -requires 'Time::Fake'; requires 'Scalar::Util'; requires 'DBIx::Class'; requires 'DBIx::Class::PassphraseColumn'; @@ -25,6 +24,11 @@ requires 'GIS::Distance'; requires 'Text::CSV'; requires 'Try::Tiny'; +on 'test' => sub { + requires 'Test::More'; + requires 'Test::MockTime'; +}; + feature 'schema-graph', 'Draw diagrams of Schema' => sub { requires 'GraphViz'; requires 'SQL::Translator'; @@ -38,4 +42,3 @@ feature 'postgres', 'PostgreSQL Support' => sub { feature 'codepoint-open', 'Code Point Open manipulation' => sub { requires 'Geo::UK::Postcode::CodePointOpen'; }; - diff --git a/t/api/stats.t b/t/api/stats.t index 620f5d3..4fe849b 100644 --- a/t/api/stats.t +++ b/t/api/stats.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,6 +19,8 @@ $framework->install_fixtures('users'); my $t = $framework->framework; my $schema = $t->app->schema; +set_absolute_time('2017-01-01T00:00:00Z'); + my $start = DateTime->today->subtract( hours => 12 ); # create 40 days worth of data @@ -45,7 +51,7 @@ $t->post_ok('/api/stats/customer' => json => { }) ->status_is(200)->or($framework->dump_error) ->json_is('/weeks', { - purchases => [ 8, 21, 19, 22, 20, 20, 8 ], + purchases => [ 2, 21, 20, 21, 19, 22, 13 ], }) ->json_is('/sectors', { sectors => ['A'], From 713fee37d6ba3504efa37a4757d275d76f64b1ea Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Dec 2017 14:46:32 +0000 Subject: [PATCH 058/289] fixed counts for sqlite vs postgres --- lib/Pear/LocalLoop/Controller/Admin/Reports.pm | 5 ++++- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 10 ++++++++-- .../LocalLoop/Controller/Api/V1/Customer/Graphs.pm | 5 ++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm index aff6bc9..494cc10 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm @@ -18,7 +18,10 @@ sub transaction_data { columns => [ { quantised => $quantised_column, - count => \"COUNT(*)", + count => $c->pg_or_sqlite( + 'count', + "COUNT(*)", + ), sum_distance => $c->pg_or_sqlite( 'SUM("me"."distance")', 'SUM("me"."distance")', diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index e2b98e2..2db7371 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -86,7 +86,10 @@ sub post_customer { columns => [ { quantised => 'quantised_weeks', - count => \"COUNT(*)", + count => $c->pg_or_sqlite( + 'count', + "COUNT(*)", + ), } ], group_by => 'quantised_weeks', @@ -103,7 +106,10 @@ sub post_customer { join => { 'seller' => 'organisation' }, columns => { sector => "organisation.sector", - count => \"COUNT(*)", + count => $c->pg_or_sqlite( + 'count', + "COUNT(*)", + ), }, group_by => "organisation.sector", order_by => { '-desc' => "COUNT(*)" }, diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm index f48e52b..b461220 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm @@ -112,7 +112,10 @@ sub _purchases_avg_spend_duration { columns => [ { quantised => 'quantised_days', - count => \"COUNT(*)", + count => $c->pg_or_sqlite( + 'count', + "COUNT(*)", + ), sum_value => $c->pg_or_sqlite( 'SUM("me"."value")', 'SUM("me"."value")', From b7493af6c65320c0fae869fb880f236f5d498e93 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Dec 2017 15:08:15 +0000 Subject: [PATCH 059/289] added missing pg_or_sqlite sub --- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index 2db7371..5d5f32c 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -244,4 +244,19 @@ sub post_leaderboards_paged { }); } +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; From 9f9a79c69d5ca90bfd5f8e67e90934ee55a4065c Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Dec 2017 15:36:24 +0000 Subject: [PATCH 060/289] reverted fix and did different fix to order_by --- lib/Pear/LocalLoop/Controller/Admin/Reports.pm | 5 +---- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 12 +++--------- .../LocalLoop/Controller/Api/V1/Customer/Graphs.pm | 5 +---- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm index 494cc10..aff6bc9 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm @@ -18,10 +18,7 @@ sub transaction_data { columns => [ { quantised => $quantised_column, - count => $c->pg_or_sqlite( - 'count', - "COUNT(*)", - ), + count => \"COUNT(*)", sum_distance => $c->pg_or_sqlite( 'SUM("me"."distance")', 'SUM("me"."distance")', diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index 5d5f32c..ccbb435 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -86,10 +86,7 @@ sub post_customer { columns => [ { quantised => 'quantised_weeks', - count => $c->pg_or_sqlite( - 'count', - "COUNT(*)", - ), + count => \"COUNT(*)", } ], group_by => 'quantised_weeks', @@ -106,13 +103,10 @@ sub post_customer { join => { 'seller' => 'organisation' }, columns => { sector => "organisation.sector", - count => $c->pg_or_sqlite( - 'count', - "COUNT(*)", - ), + count => \"COUNT(*)", }, group_by => "organisation.sector", - order_by => { '-desc' => "COUNT(*)" }, + order_by => { '-desc' => $c->pg_or_sqlite('count',"COUNT(*)",)}, } ); diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm index b461220..f48e52b 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm @@ -112,10 +112,7 @@ sub _purchases_avg_spend_duration { columns => [ { quantised => 'quantised_days', - count => $c->pg_or_sqlite( - 'count', - "COUNT(*)", - ), + count => \"COUNT(*)", sum_value => $c->pg_or_sqlite( 'SUM("me"."value")', 'SUM("me"."value")', From 201594d331283396c64cb7ec4df5a3d27f750fbd Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Dec 2017 16:19:10 +0000 Subject: [PATCH 061/289] added new sector --- CHANGELOG.md | 3 ++- templates/partials/sector_options.html.ep | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c15ebd..f045580 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,8 @@ * Added API for customer local purchase pie charts * Added API for customer snippets * Added API for sector purchase list for customer dashboard -* **Admin Feature** Fixed org sector on user edit layout and text +* **Admin Fix** Fixed org sector on user edit layout and text +* **Admin Feature** Added Sector U # v0.9.7 diff --git a/templates/partials/sector_options.html.ep b/templates/partials/sector_options.html.ep index 625e89f..0c84578 100644 --- a/templates/partials/sector_options.html.ep +++ b/templates/partials/sector_options.html.ep @@ -19,3 +19,4 @@ + From 17ba1e75fd645bb8235104ee5f7000aaed7b49dc Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 19 Dec 2017 18:03:15 +0000 Subject: [PATCH 062/289] frontpage stats amended for sectors and weeks --- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 102 ++++++++++++--------- t/api/stats.t | 8 +- 2 files changed, 64 insertions(+), 46 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index ccbb435..8545406 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -1,7 +1,7 @@ package Pear::LocalLoop::Controller::Api::Stats; use Mojo::Base 'Mojolicious::Controller'; -use List::Util qw/ first /; +use List::Util qw/ max sum /; has error_messages => sub { return { @@ -67,9 +67,6 @@ sub post_customer { my $end = DateTime->today; my $start = $end->clone->subtract_duration( $duration ); - my $weeks = { purchases => [] }; - my $sectors = { sectors => [], purchases => [] }; - my $dtf = $c->schema->storage->datetime_parser; my $driver = $c->schema->storage->dbh->{Driver}->{Name}; my $week_transaction_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( @@ -94,9 +91,22 @@ sub post_customer { } ); - for ( $week_transaction_rs->all ) { - push @{ $weeks->{ purchases } }, ($_->get_column('count') || 0); - } + my @all_weeks = $week_transaction_rs->all; + my $first = $all_weeks[0]->get_column('count') || 0; + my $second = $all_weeks[1]->get_column('count') || 0; + my $max = max( map { $_->get_column('count') } @all_weeks ); + my $sum = sum( map { $_->get_column('count') } @all_weeks ); + my $count = $week_transaction_rs->count; + + my $weeks = { + first => $first, + second => $second, + max => $max, + sum => $sum, + count => $count, + }; + + my $sectors = { sectors => [], purchases => [] }; my $sector_purchase_rs = $entity->purchases->search({}, { @@ -189,52 +199,58 @@ sub post_leaderboards_paged { my $page = 1; my $today_board = $leaderboard_rs->get_latest( $validation->param('type') ); + my @leaderboard_array; + my $current_user_position; + my $values_count = 0; + if ( defined $today_board ) { + + if ( !defined $validation->param('page') || $validation->param('page') < 1 ) { + my $user_position = $today_board->values->find({ entity_id => $c->stash->{api_user}->entity->id }); + $page = int(defined $user_position ? $user_position->{position} : 0 / 10) + 1; + } else { + $page = $validation->param('page'); + } - if ( !defined $validation->param('page') || $validation->param('page') < 1 ) { - my $user_position = $today_board->values->find({ entity_id => $c->stash->{api_user}->entity->id }); - $page = int(defined $user_position ? $user_position->{position} : 0 / 10) + 1; - } else { - $page = $validation->param('page'); - } - - my $today_values = $today_board->values->search( - {}, - { - page => $page, - rows => 10, - order_by => { -asc => 'me.position' }, - columns => [ - qw/ - me.value - me.trend - me.position - /, - { display_name => 'customer.display_name' }, - ], - join => { entity => 'customer' }, - }, - ); - $today_values->result_class( 'DBIx::Class::ResultClass::HashRefInflator' ); + my $today_values = $today_board->values->search( + {}, + { + page => $page, + rows => 10, + order_by => { -asc => 'me.position' }, + columns => [ + qw/ + me.value + me.trend + me.position + /, + { display_name => 'customer.display_name' }, + ], + join => { entity => 'customer' }, + }, + ); + $today_values->result_class( 'DBIx::Class::ResultClass::HashRefInflator' ); - my @leaderboard_array = $today_values->all; + @leaderboard_array = $today_values->all; - if ( $validation->param('type') =~ /total$/ ) { - @leaderboard_array = (map { - { - %$_, - value => $_->{value} / 100000, - } - } @leaderboard_array); - } + $values_count = $today_values->pager->total_entries; - my $current_user_position = $today_values->find({ entity_id => $c->stash->{api_user}->entity->id }); + if ( $validation->param('type') =~ /total$/ ) { + @leaderboard_array = (map { + { + %$_, + value => $_->{value} / 100000, + } + } @leaderboard_array); + } + $current_user_position = $today_values->find({ entity_id => $c->stash->{api_user}->entity->id }); + } return $c->render( json => { success => Mojo::JSON->true, leaderboard => [ @leaderboard_array ], user_position => defined $current_user_position ? $current_user_position->{position} : 0, page => $page, - count => $today_values->pager->total_entries, + count => $values_count, }); } diff --git a/t/api/stats.t b/t/api/stats.t index 4fe849b..3df45c8 100644 --- a/t/api/stats.t +++ b/t/api/stats.t @@ -44,14 +44,16 @@ my $session_key = $framework->login({ password => 'abc123', }); -#TODO be able to define start and end below in request - $t->post_ok('/api/stats/customer' => json => { session_key => $session_key, }) ->status_is(200)->or($framework->dump_error) ->json_is('/weeks', { - purchases => [ 2, 21, 20, 21, 19, 22, 13 ], + first => 2, + second => 21, + max => 22, + sum => 118, + count => 7, }) ->json_is('/sectors', { sectors => ['A'], From 44155cd33e7b596107011bb8db2e531204d89f84 Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 21 Dec 2017 15:39:34 +0000 Subject: [PATCH 063/289] updated changelog --- CHANGELOG.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 181cfda..6eaefaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,8 @@ # Next Release -# v0.10.0 +# v0.10.1 -* **API Change** Updated API for story trail maps -* **Admin Feature** Improved links in relevant places to automatically open in - a new tab -* **Admin Feature** Ability to add ESTA to entity Added -* Trail map code updated * Added API for customer graphs * Revamped graphs code * Added API for customer local purchase pie charts @@ -17,6 +12,14 @@ * **Admin Fix** Fixed org sector on user edit layout and text * **Admin Feature** Added Sector U +# v0.10.0 + +* **API Change** Updated API for story trail maps +* **Admin Feature** Improved links in relevant places to automatically open in + a new tab +* **Admin Feature** Ability to add ESTA to entity Added +* Trail map code updated + # v0.9.7 * **Admin Fix**: Fix error in Importing under Postgres From 69811229c8df28a60c05d97c790474ab266db714 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 2 Jan 2018 19:56:10 +0000 Subject: [PATCH 064/289] Fix booleans on sqlite ddl --- share/ddl/SQLite/deploy/18/001-auto.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/share/ddl/SQLite/deploy/18/001-auto.sql b/share/ddl/SQLite/deploy/18/001-auto.sql index bcdd2dd..64083e5 100644 --- a/share/ddl/SQLite/deploy/18/001-auto.sql +++ b/share/ddl/SQLite/deploy/18/001-auto.sql @@ -95,7 +95,7 @@ CREATE TABLE organisations ( postcode varchar(16), country varchar(255), sector varchar(1), - pending boolean NOT NULL DEFAULT false, + pending boolean NOT NULL DEFAULT 0, is_local boolean, submitted_by_id integer, latitude decimal(8,5), @@ -129,7 +129,7 @@ CREATE TABLE users ( email text NOT NULL, join_date datetime NOT NULL, password varchar(100) NOT NULL, - is_admin boolean NOT NULL DEFAULT false, + is_admin boolean NOT NULL DEFAULT 0, FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE ); CREATE INDEX users_idx_entity_id ON users (entity_id); @@ -146,7 +146,7 @@ CREATE TABLE feedback ( package_name varchar(255) NOT NULL, version_code varchar(255) NOT NULL, version_number varchar(255) NOT NULL, - actioned boolean NOT NULL DEFAULT false, + actioned boolean NOT NULL DEFAULT 0, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION ); CREATE INDEX feedback_idx_user_id ON feedback (user_id); @@ -204,7 +204,7 @@ CREATE TABLE import_values ( purchase_value varchar(255) NOT NULL, org_name varchar(255) NOT NULL, transaction_id integer, - ignore_value boolean NOT NULL DEFAULT false, + ignore_value boolean NOT NULL DEFAULT 0, FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION ); From e29badb59dd83df9dfb24dbc801e2386d9088e96 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 2 Jan 2018 19:56:48 +0000 Subject: [PATCH 065/289] Added is_fair column for fairly trading organisations --- lib/Pear/LocalLoop/Schema.pm | 2 +- .../LocalLoop/Schema/Result/Organisation.pm | 5 + .../deploy/19/001-auto-__VERSION.sql | 18 + share/ddl/PostgreSQL/deploy/19/001-auto.sql | 330 ++++ .../ddl/PostgreSQL/upgrade/18-19/001-auto.sql | 12 + .../SQLite/deploy/19/001-auto-__VERSION.sql | 18 + share/ddl/SQLite/deploy/19/001-auto.sql | 230 +++ share/ddl/SQLite/upgrade/18-19/001-auto.sql | 12 + .../_source/deploy/19/001-auto-__VERSION.yml | 91 + share/ddl/_source/deploy/19/001-auto.yml | 1734 +++++++++++++++++ 10 files changed, 2451 insertions(+), 1 deletion(-) create mode 100644 share/ddl/PostgreSQL/deploy/19/001-auto-__VERSION.sql create mode 100644 share/ddl/PostgreSQL/deploy/19/001-auto.sql create mode 100644 share/ddl/PostgreSQL/upgrade/18-19/001-auto.sql create mode 100644 share/ddl/SQLite/deploy/19/001-auto-__VERSION.sql create mode 100644 share/ddl/SQLite/deploy/19/001-auto.sql create mode 100644 share/ddl/SQLite/upgrade/18-19/001-auto.sql create mode 100644 share/ddl/_source/deploy/19/001-auto-__VERSION.yml create mode 100644 share/ddl/_source/deploy/19/001-auto.yml diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index 2d35b1b..8552b6b 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -6,7 +6,7 @@ use warnings; use base 'DBIx::Class::Schema'; -our $VERSION = 18; +our $VERSION = 19; __PACKAGE__->load_namespaces; diff --git a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm index 98b75c5..cdd71db 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm @@ -59,6 +59,11 @@ __PACKAGE__->add_columns( default => undef, is_nullable => 1, }, + is_fair => { + data_type => 'boolean', + default => undef, + is_nullable => 1, + }, submitted_by_id => { data_type => 'integer', is_nullable => 1, diff --git a/share/ddl/PostgreSQL/deploy/19/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/19/001-auto-__VERSION.sql new file mode 100644 index 0000000..fa0261a --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/19/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Tue Jan 2 19:51:55 2018 +-- +; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE "dbix_class_deploymenthandler_versions" ( + "id" serial NOT NULL, + "version" character varying(50) NOT NULL, + "ddl" text, + "upgrade_sql" text, + PRIMARY KEY ("id"), + CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version") +); + +; diff --git a/share/ddl/PostgreSQL/deploy/19/001-auto.sql b/share/ddl/PostgreSQL/deploy/19/001-auto.sql new file mode 100644 index 0000000..eac764e --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/19/001-auto.sql @@ -0,0 +1,330 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Tue Jan 2 19:51:55 2018 +-- +; +-- +-- Table: account_tokens +-- +CREATE TABLE "account_tokens" ( + "id" serial NOT NULL, + "name" text NOT NULL, + "used" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "account_tokens_name" UNIQUE ("name") +); + +; +-- +-- Table: entities +-- +CREATE TABLE "entities" ( + "id" serial NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: gb_postcodes +-- +CREATE TABLE "gb_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) DEFAULT '' NOT NULL, + "latitude" numeric(7,5), + "longitude" numeric(7,5), + PRIMARY KEY ("outcode", "incode") +); + +; +-- +-- Table: import_sets +-- +CREATE TABLE "import_sets" ( + "id" serial NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: leaderboards +-- +CREATE TABLE "leaderboards" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboards_type" UNIQUE ("type") +); + +; +-- +-- Table: customers +-- +CREATE TABLE "customers" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "display_name" character varying(255) NOT NULL, + "full_name" character varying(255) NOT NULL, + "year_of_birth" integer NOT NULL, + "postcode" character varying(16) NOT NULL, + "latitude" numeric(5,2), + "longitude" numeric(5,2), + PRIMARY KEY ("id") +); +CREATE INDEX "customers_idx_entity_id" on "customers" ("entity_id"); + +; +-- +-- Table: entity_association +-- +CREATE TABLE "entity_association" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "lis" boolean, + "esta" boolean, + PRIMARY KEY ("id") +); +CREATE INDEX "entity_association_idx_entity_id" on "entity_association" ("entity_id"); + +; +-- +-- Table: leaderboard_sets +-- +CREATE TABLE "leaderboard_sets" ( + "id" serial NOT NULL, + "leaderboard_id" integer NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "leaderboard_sets_idx_leaderboard_id" on "leaderboard_sets" ("leaderboard_id"); + +; +-- +-- Table: organisations +-- +CREATE TABLE "organisations" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "street_name" text, + "town" character varying(255) NOT NULL, + "postcode" character varying(16), + "country" character varying(255), + "sector" character varying(1), + "pending" boolean DEFAULT false NOT NULL, + "is_local" boolean, + "is_fair" boolean, + "submitted_by_id" integer, + "latitude" numeric(8,5), + "longitude" numeric(8,5), + PRIMARY KEY ("id") +); +CREATE INDEX "organisations_idx_entity_id" on "organisations" ("entity_id"); + +; +-- +-- Table: transactions +-- +CREATE TABLE "transactions" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "proof_image" text, + "submitted_at" timestamp NOT NULL, + "purchase_time" timestamp NOT NULL, + "distance" numeric(15), + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_idx_buyer_id" on "transactions" ("buyer_id"); +CREATE INDEX "transactions_idx_seller_id" on "transactions" ("seller_id"); + +; +-- +-- Table: users +-- +CREATE TABLE "users" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "email" text NOT NULL, + "join_date" timestamp NOT NULL, + "password" character varying(100) NOT NULL, + "is_admin" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "users_email" UNIQUE ("email") +); +CREATE INDEX "users_idx_entity_id" on "users" ("entity_id"); + +; +-- +-- Table: feedback +-- +CREATE TABLE "feedback" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "feedbacktext" text NOT NULL, + "app_name" character varying(255) NOT NULL, + "package_name" character varying(255) NOT NULL, + "version_code" character varying(255) NOT NULL, + "version_number" character varying(255) NOT NULL, + "actioned" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "feedback_idx_user_id" on "feedback" ("user_id"); + +; +-- +-- Table: import_lookups +-- +CREATE TABLE "import_lookups" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_lookups_idx_entity_id" on "import_lookups" ("entity_id"); +CREATE INDEX "import_lookups_idx_set_id" on "import_lookups" ("set_id"); + +; +-- +-- Table: organisation_payroll +-- +CREATE TABLE "organisation_payroll" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "entry_period" timestamp NOT NULL, + "employee_amount" integer NOT NULL, + "local_employee_amount" integer NOT NULL, + "gross_payroll" numeric(100,0) NOT NULL, + "payroll_income_tax" numeric(100,0) NOT NULL, + "payroll_employee_ni" numeric(100,0) NOT NULL, + "payroll_employer_ni" numeric(100,0) NOT NULL, + "payroll_total_pension" numeric(100,0) NOT NULL, + "payroll_other_benefit" numeric(100,0) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisation_payroll_idx_org_id" on "organisation_payroll" ("org_id"); + +; +-- +-- Table: session_tokens +-- +CREATE TABLE "session_tokens" ( + "id" serial NOT NULL, + "token" character varying(255) NOT NULL, + "user_id" integer NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "session_tokens_token" UNIQUE ("token") +); +CREATE INDEX "session_tokens_idx_user_id" on "session_tokens" ("user_id"); + +; +-- +-- Table: import_values +-- +CREATE TABLE "import_values" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "user_name" character varying(255) NOT NULL, + "purchase_date" timestamp NOT NULL, + "purchase_value" character varying(255) NOT NULL, + "org_name" character varying(255) NOT NULL, + "transaction_id" integer, + "ignore_value" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_values_idx_set_id" on "import_values" ("set_id"); +CREATE INDEX "import_values_idx_transaction_id" on "import_values" ("transaction_id"); + +; +-- +-- Table: leaderboard_values +-- +CREATE TABLE "leaderboard_values" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "set_id" integer NOT NULL, + "position" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "trend" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboard_values_entity_id_set_id" UNIQUE ("entity_id", "set_id") +); +CREATE INDEX "leaderboard_values_idx_entity_id" on "leaderboard_values" ("entity_id"); +CREATE INDEX "leaderboard_values_idx_set_id" on "leaderboard_values" ("set_id"); + +; +-- +-- Foreign Key Definitions +-- + +; +ALTER TABLE "customers" ADD CONSTRAINT "customers_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entity_association" ADD CONSTRAINT "entity_association_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "leaderboard_sets" ADD CONSTRAINT "leaderboard_sets_fk_leaderboard_id" FOREIGN KEY ("leaderboard_id") + REFERENCES "leaderboards" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "users" ADD CONSTRAINT "users_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "feedback" ADD CONSTRAINT "feedback_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisation_payroll" ADD CONSTRAINT "organisation_payroll_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") DEFERRABLE; + +; +ALTER TABLE "session_tokens" ADD CONSTRAINT "session_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "leaderboard_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; diff --git a/share/ddl/PostgreSQL/upgrade/18-19/001-auto.sql b/share/ddl/PostgreSQL/upgrade/18-19/001-auto.sql new file mode 100644 index 0000000..4669b5b --- /dev/null +++ b/share/ddl/PostgreSQL/upgrade/18-19/001-auto.sql @@ -0,0 +1,12 @@ +-- Convert schema 'share\ddl\_source\deploy\18\001-auto.yml' to 'share\ddl\_source\deploy\19\001-auto.yml':; + +; +BEGIN; + +; +ALTER TABLE organisations ADD COLUMN is_fair boolean; + +; + +COMMIT; + diff --git a/share/ddl/SQLite/deploy/19/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/19/001-auto-__VERSION.sql new file mode 100644 index 0000000..dc76bf8 --- /dev/null +++ b/share/ddl/SQLite/deploy/19/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Tue Jan 2 19:51:55 2018 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE dbix_class_deploymenthandler_versions ( + id INTEGER PRIMARY KEY NOT NULL, + version varchar(50) NOT NULL, + ddl text, + upgrade_sql text +); +CREATE UNIQUE INDEX dbix_class_deploymenthandler_versions_version ON dbix_class_deploymenthandler_versions (version); +COMMIT; diff --git a/share/ddl/SQLite/deploy/19/001-auto.sql b/share/ddl/SQLite/deploy/19/001-auto.sql new file mode 100644 index 0000000..185f4fa --- /dev/null +++ b/share/ddl/SQLite/deploy/19/001-auto.sql @@ -0,0 +1,230 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Tue Jan 2 19:51:55 2018 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: account_tokens +-- +CREATE TABLE account_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + name text NOT NULL, + used integer NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX account_tokens_name ON account_tokens (name); +-- +-- Table: entities +-- +CREATE TABLE entities ( + id INTEGER PRIMARY KEY NOT NULL, + type varchar(255) NOT NULL +); +-- +-- Table: gb_postcodes +-- +CREATE TABLE gb_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL DEFAULT '', + latitude decimal(7,5), + longitude decimal(7,5), + PRIMARY KEY (outcode, incode) +); +-- +-- Table: import_sets +-- +CREATE TABLE import_sets ( + id INTEGER PRIMARY KEY NOT NULL, + date datetime NOT NULL +); +-- +-- Table: leaderboards +-- +CREATE TABLE leaderboards ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + type varchar(255) NOT NULL +); +CREATE UNIQUE INDEX leaderboards_type ON leaderboards (type); +-- +-- Table: customers +-- +CREATE TABLE customers ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + display_name varchar(255) NOT NULL, + full_name varchar(255) NOT NULL, + year_of_birth integer NOT NULL, + postcode varchar(16) NOT NULL, + latitude decimal(5,2), + longitude decimal(5,2), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX customers_idx_entity_id ON customers (entity_id); +-- +-- Table: entity_association +-- +CREATE TABLE entity_association ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + lis boolean, + esta boolean, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX entity_association_idx_entity_id ON entity_association (entity_id); +-- +-- Table: leaderboard_sets +-- +CREATE TABLE leaderboard_sets ( + id INTEGER PRIMARY KEY NOT NULL, + leaderboard_id integer NOT NULL, + date datetime NOT NULL, + FOREIGN KEY (leaderboard_id) REFERENCES leaderboards(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_sets_idx_leaderboard_id ON leaderboard_sets (leaderboard_id); +-- +-- Table: organisations +-- +CREATE TABLE organisations ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + name varchar(255) NOT NULL, + street_name text, + town varchar(255) NOT NULL, + postcode varchar(16), + country varchar(255), + sector varchar(1), + pending boolean NOT NULL DEFAULT 0, + is_local boolean, + is_fair boolean, + submitted_by_id integer, + latitude decimal(8,5), + longitude decimal(8,5), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX organisations_idx_entity_id ON organisations (entity_id); +-- +-- Table: transactions +-- +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + distance numeric(15), + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transactions_idx_buyer_id ON transactions (buyer_id); +CREATE INDEX transactions_idx_seller_id ON transactions (seller_id); +-- +-- Table: users +-- +CREATE TABLE users ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + email text NOT NULL, + join_date datetime NOT NULL, + password varchar(100) NOT NULL, + is_admin boolean NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX users_idx_entity_id ON users (entity_id); +CREATE UNIQUE INDEX users_email ON users (email); +-- +-- Table: feedback +-- +CREATE TABLE feedback ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + submitted_at datetime NOT NULL, + feedbacktext text NOT NULL, + app_name varchar(255) NOT NULL, + package_name varchar(255) NOT NULL, + version_code varchar(255) NOT NULL, + version_number varchar(255) NOT NULL, + actioned boolean NOT NULL DEFAULT 0, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX feedback_idx_user_id ON feedback (user_id); +-- +-- Table: import_lookups +-- +CREATE TABLE import_lookups ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + name varchar(255) NOT NULL, + entity_id integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_lookups_idx_entity_id ON import_lookups (entity_id); +CREATE INDEX import_lookups_idx_set_id ON import_lookups (set_id); +-- +-- Table: organisation_payroll +-- +CREATE TABLE organisation_payroll ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + submitted_at datetime NOT NULL, + entry_period datetime NOT NULL, + employee_amount integer NOT NULL, + local_employee_amount integer NOT NULL, + gross_payroll numeric(100,0) NOT NULL, + payroll_income_tax numeric(100,0) NOT NULL, + payroll_employee_ni numeric(100,0) NOT NULL, + payroll_employer_ni numeric(100,0) NOT NULL, + payroll_total_pension numeric(100,0) NOT NULL, + payroll_other_benefit numeric(100,0) NOT NULL, + FOREIGN KEY (org_id) REFERENCES organisations(id) +); +CREATE INDEX organisation_payroll_idx_org_id ON organisation_payroll (org_id); +-- +-- Table: session_tokens +-- +CREATE TABLE session_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + token varchar(255) NOT NULL, + user_id integer NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX session_tokens_idx_user_id ON session_tokens (user_id); +CREATE UNIQUE INDEX session_tokens_token ON session_tokens (token); +-- +-- Table: import_values +-- +CREATE TABLE import_values ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + user_name varchar(255) NOT NULL, + purchase_date datetime NOT NULL, + purchase_value varchar(255) NOT NULL, + org_name varchar(255) NOT NULL, + transaction_id integer, + ignore_value boolean NOT NULL DEFAULT 0, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_values_idx_set_id ON import_values (set_id); +CREATE INDEX import_values_idx_transaction_id ON import_values (transaction_id); +-- +-- Table: leaderboard_values +-- +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_values_idx_entity_id ON leaderboard_values (entity_id); +CREATE INDEX leaderboard_values_idx_set_id ON leaderboard_values (set_id); +CREATE UNIQUE INDEX leaderboard_values_entity_id_set_id ON leaderboard_values (entity_id, set_id); +COMMIT; diff --git a/share/ddl/SQLite/upgrade/18-19/001-auto.sql b/share/ddl/SQLite/upgrade/18-19/001-auto.sql new file mode 100644 index 0000000..4669b5b --- /dev/null +++ b/share/ddl/SQLite/upgrade/18-19/001-auto.sql @@ -0,0 +1,12 @@ +-- Convert schema 'share\ddl\_source\deploy\18\001-auto.yml' to 'share\ddl\_source\deploy\19\001-auto.yml':; + +; +BEGIN; + +; +ALTER TABLE organisations ADD COLUMN is_fair boolean; + +; + +COMMIT; + diff --git a/share/ddl/_source/deploy/19/001-auto-__VERSION.yml b/share/ddl/_source/deploy/19/001-auto-__VERSION.yml new file mode 100644 index 0000000..907f443 --- /dev/null +++ b/share/ddl/_source/deploy/19/001-auto-__VERSION.yml @@ -0,0 +1,91 @@ +--- +schema: + procedures: {} + tables: + dbix_class_deploymenthandler_versions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - version + match_type: '' + name: dbix_class_deploymenthandler_versions_version + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + ddl: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ddl + order: 3 + size: + - 0 + id: + data_type: int + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + upgrade_sql: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: upgrade_sql + order: 4 + size: + - 0 + version: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: version + order: 2 + size: + - 50 + indices: [] + name: dbix_class_deploymenthandler_versions + options: [] + order: 1 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - __VERSION + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 diff --git a/share/ddl/_source/deploy/19/001-auto.yml b/share/ddl/_source/deploy/19/001-auto.yml new file mode 100644 index 0000000..65c4a19 --- /dev/null +++ b/share/ddl/_source/deploy/19/001-auto.yml @@ -0,0 +1,1734 @@ +--- +schema: + procedures: {} + tables: + account_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: account_tokens_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 0 + used: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: used + order: 3 + size: + - 0 + indices: [] + name: account_tokens + options: [] + order: 1 + customers: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: customers_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + display_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: display_name + order: 3 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + full_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 4 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 7 + size: + - 5 + - 2 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 8 + size: + - 5 + - 2 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + year_of_birth: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: year_of_birth + order: 5 + size: + - 0 + indices: + - fields: + - entity_id + name: customers_idx_entity_id + options: [] + type: NORMAL + name: customers + options: [] + order: 6 + entities: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: type + order: 2 + size: + - 255 + indices: [] + name: entities + options: [] + order: 2 + entity_association: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entity_association_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + esta: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: esta + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + lis: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: lis + order: 3 + size: + - 0 + indices: + - fields: + - entity_id + name: entity_association_idx_entity_id + options: [] + type: NORMAL + name: entity_association + options: [] + order: 7 + feedback: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: feedback_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + actioned: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: actioned + order: 9 + size: + - 0 + app_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: app_name + order: 5 + size: + - 255 + feedbacktext: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: feedbacktext + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + package_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: package_name + order: 6 + size: + - 255 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + version_code: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_code + order: 7 + size: + - 255 + version_number: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_number + order: 8 + size: + - 255 + indices: + - fields: + - user_id + name: feedback_idx_user_id + options: [] + type: NORMAL + name: feedback + options: [] + order: 12 + gb_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + incode: + data_type: char + default_value: '' + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 3 + size: + - 7 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 4 + size: + - 7 + - 5 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + indices: [] + name: gb_postcodes + options: [] + order: 3 + import_lookups: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: import_lookups_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_lookups_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + indices: + - fields: + - entity_id + name: import_lookups_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: import_lookups_idx_set_id + options: [] + type: NORMAL + name: import_lookups + options: [] + order: 13 + import_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: import_sets + options: [] + order: 4 + import_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: import_values_fk_transaction_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ignore_value: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ignore_value + order: 8 + size: + - 0 + org_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_name + order: 6 + size: + - 255 + purchase_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_date + order: 4 + size: + - 0 + purchase_value: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_value + order: 5 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 7 + size: + - 0 + user_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_name + order: 3 + size: + - 255 + indices: + - fields: + - set_id + name: import_values_idx_set_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: import_values_idx_transaction_id + options: [] + type: NORMAL + name: import_values + options: [] + order: 16 + leaderboard_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - leaderboard_id + match_type: '' + name: leaderboard_sets_fk_leaderboard_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboards + type: FOREIGN KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + leaderboard_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: leaderboard_id + order: 2 + size: + - 0 + indices: + - fields: + - leaderboard_id + name: leaderboard_sets_idx_leaderboard_id + options: [] + type: NORMAL + name: leaderboard_sets + options: [] + order: 8 + leaderboard_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + - set_id + match_type: '' + name: leaderboard_values_entity_id_set_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - entity_id + match_type: '' + name: leaderboard_values_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: leaderboard_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboard_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + position: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: position + order: 4 + size: + - 0 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: set_id + order: 3 + size: + - 0 + trend: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: trend + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 5 + size: + - 100 + - 0 + indices: + - fields: + - entity_id + name: leaderboard_values_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: leaderboard_values_idx_set_id + options: [] + type: NORMAL + name: leaderboard_values + options: [] + order: 17 + leaderboards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - type + match_type: '' + name: leaderboards_type + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 255 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: type + order: 3 + size: + - 255 + indices: [] + name: leaderboards + options: [] + order: 5 + organisation_payroll: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisation_payroll_fk_org_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: employee_amount + order: 5 + size: + - 0 + entry_period: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entry_period + order: 4 + size: + - 0 + gross_payroll: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_payroll + order: 7 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_employee_amount + order: 6 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + payroll_employee_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employee_ni + order: 9 + size: + - 100 + - 0 + payroll_employer_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employer_ni + order: 10 + size: + - 100 + - 0 + payroll_income_tax: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_income_tax + order: 8 + size: + - 100 + - 0 + payroll_other_benefit: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_other_benefit + order: 12 + size: + - 100 + - 0 + payroll_total_pension: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_total_pension + order: 11 + size: + - 100 + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + indices: + - fields: + - org_id + name: organisation_payroll_idx_org_id + options: [] + type: NORMAL + name: organisation_payroll + options: [] + order: 14 + organisations: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: organisations_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + country: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: country + order: 7 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_fair: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_fair + order: 11 + size: + - 0 + is_local: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_local + order: 10 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 13 + size: + - 8 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 14 + size: + - 8 + - 5 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + pending: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: pending + order: 9 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + sector: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: sector + order: 8 + size: + - 1 + street_name: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: street_name + order: 4 + size: + - 0 + submitted_by_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: submitted_by_id + order: 12 + size: + - 0 + town: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: town + order: 5 + size: + - 255 + indices: + - fields: + - entity_id + name: organisations_idx_entity_id + options: [] + type: NORMAL + name: organisations + options: [] + order: 9 + session_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - token + match_type: '' + name: session_tokens_token + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: session_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: token + order: 2 + size: + - 255 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 3 + size: + - 0 + indices: + - fields: + - user_id + name: session_tokens_idx_user_id + options: [] + type: NORMAL + name: session_tokens + options: [] + order: 15 + transactions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transactions_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transactions_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 8 + size: + - 15 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + proof_image: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: proof_image + order: 5 + size: + - 0 + purchase_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_time + order: 7 + size: + - 0 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transactions_idx_buyer_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transactions_idx_seller_id + options: [] + type: NORMAL + name: transactions + options: [] + order: 10 + users: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: users_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: users_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 3 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_admin: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_admin + order: 6 + size: + - 0 + join_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: join_date + order: 4 + size: + - 0 + password: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: password + order: 5 + size: + - 100 + indices: + - fields: + - entity_id + name: users_idx_entity_id + options: [] + type: NORMAL + name: users + options: [] + order: 11 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - AccountToken + - Customer + - Entity + - EntityAssociation + - Feedback + - GbPostcode + - ImportLookup + - ImportSet + - ImportValue + - Leaderboard + - LeaderboardSet + - LeaderboardValue + - Organisation + - OrganisationPayroll + - SessionToken + - Transaction + - User + - ViewQuantisedTransactionPg + - ViewQuantisedTransactionSQLite + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 From 725bebb00ba5945c5b35f928e0b525b460b85874 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 2 Jan 2018 19:57:12 +0000 Subject: [PATCH 066/289] Added fairly trading org field and change org transactions to show purchases not sales --- .../Controller/Admin/Organisations.pm | 6 +++++- templates/admin/organisations/add_org.html.ep | 18 ++++++++++++++++++ templates/admin/organisations/list.html.ep | 7 +++++++ .../admin/organisations/valid_read.html.ep | 9 +++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 7a42d10..69ce211 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -41,6 +41,7 @@ sub add_org_submit { $validation->optional('postcode')->postcode; $validation->optional('pending'); $validation->optional('is_local'); + $validation->optional('is_fair'); if ( $validation->has_error ) { $c->flash( error => 'The validation has failed' ); @@ -60,6 +61,7 @@ sub add_org_submit { submitted_by_id => $c->current_user->id, pending => defined $validation->param('pending') ? 0 : 1, is_local => $validation->param('is_local'), + is_fair => $validation->param('is_fair'), }, type => 'organisation', }); @@ -78,7 +80,7 @@ sub add_org_submit { sub valid_read { my $c = shift; my $valid_org = $c->schema->resultset('Organisation')->find( $c->param('id') ); - my $transactions = $valid_org->entity->sales->search( + my $transactions = $valid_org->entity->purchases->search( undef, { page => $c->param('page') || 1, rows => 10, @@ -109,6 +111,7 @@ sub valid_edit { $validation->required('postcode')->postcode; $validation->optional('pending'); $validation->optional('is_local'); + $validation->optional('is_fair'); $validation->optional('is_lis'); $validation->optional('is_esta'); @@ -129,6 +132,7 @@ sub valid_edit { postcode => $validation->param('postcode'), pending => defined $validation->param('pending') ? 0 : 1, is_local => $validation->param('is_local'), + is_fair => $validation->param('is_fair'), }); $valid_org->entity->update_or_create_related( 'associations', { lis => $validation->param('is_lis'), diff --git a/templates/admin/organisations/add_org.html.ep b/templates/admin/organisations/add_org.html.ep index be22d3c..7a964a8 100644 --- a/templates/admin/organisations/add_org.html.ep +++ b/templates/admin/organisations/add_org.html.ep @@ -55,6 +55,24 @@
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
From d331fe41fe369aa487cc014c4d43f7849d684468 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 2 Jan 2018 20:05:27 +0000 Subject: [PATCH 067/289] Added testing with postgres to travis --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fb4ae32..d8d93ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,18 @@ sudo: false language: perl + +addons: + postgresql: "9.6" + perl: - "5.20" env: - HARNESS_PERL_SWITCHES="-MDevel::Cover" install: - - cpanm --quiet --notest --installdeps . + - cpanm --quiet --notest --installdeps --with-feature=postgres . - cpanm Devel::Cover script: - prove -lr + - PEAR_TEST_PG=1 prove -lr - cover From 44ade264c943c86727e7a8f340128e722804c371 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 2 Jan 2018 21:40:41 +0000 Subject: [PATCH 068/289] Added error dump on failing test for debugging --- t/api/stats.t | 1 + 1 file changed, 1 insertion(+) diff --git a/t/api/stats.t b/t/api/stats.t index 3df45c8..67e8705 100644 --- a/t/api/stats.t +++ b/t/api/stats.t @@ -55,6 +55,7 @@ $t->post_ok('/api/stats/customer' => json => { sum => 118, count => 7, }) + ->or($framework->dump_error) ->json_is('/sectors', { sectors => ['A'], purchases => [118], From 60a41c964551d20046012ff12c3e727293442f76 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 2 Jan 2018 21:58:20 +0000 Subject: [PATCH 069/289] Disable postgres tests while investigating unrelated issue to current branch --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index d8d93ce..0b9a6c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,17 +2,17 @@ sudo: false language: perl -addons: - postgresql: "9.6" +#addons: +# postgresql: "9.6" perl: - "5.20" env: - HARNESS_PERL_SWITCHES="-MDevel::Cover" install: - - cpanm --quiet --notest --installdeps --with-feature=postgres . + - cpanm --quiet --notest --installdeps . #--with-feature=postgres . - cpanm Devel::Cover script: - prove -lr - - PEAR_TEST_PG=1 prove -lr + #- PEAR_TEST_PG=1 prove -lr - cover From 6dd574e046766b5f4ce39d3438340dec17def540 Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Tue, 2 Jan 2018 22:12:38 +0000 Subject: [PATCH 070/289] Add missed location updating in organisation edit on admin backend --- lib/Pear/LocalLoop/Controller/Admin/Organisations.pm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 69ce211..ad45129 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -50,6 +50,11 @@ sub add_org_submit { my $organisation; + my $location = $c->get_location_from_postcode( + $validation->param('postcode'), + 'organisation', + ); + try { my $entity = $c->schema->resultset('Entity')->create({ organisation => { @@ -58,6 +63,7 @@ sub add_org_submit { town => $validation->param('town'), sector => $validation->param('sector'), postcode => $validation->param('postcode'), + ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), submitted_by_id => $c->current_user->id, pending => defined $validation->param('pending') ? 0 : 1, is_local => $validation->param('is_local'), @@ -122,6 +128,11 @@ sub valid_edit { my $valid_org = $c->schema->resultset('Organisation')->find( $c->param('id') ); + my $location = $c->get_location_from_postcode( + $validation->param('postcode'), + 'organisation', + ); + try { $c->schema->storage->txn_do( sub { $valid_org->update({ @@ -130,6 +141,7 @@ sub valid_edit { town => $validation->param('town'), sector => $validation->param('sector'), postcode => $validation->param('postcode'), + ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), pending => defined $validation->param('pending') ? 0 : 1, is_local => $validation->param('is_local'), is_fair => $validation->param('is_fair'), From 4c50bfaf63b3ddff7209d3b9bbdbbbd563791ce5 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Wed, 3 Jan 2018 14:23:26 +0000 Subject: [PATCH 071/289] Updated Changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6eaefaa..7439be5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ # Next Release +# v0.10.2 + +* Added fairly traded column for organisations +* **Admin Fix** Fix issue with setting location on Admin side + # v0.10.1 * Added API for customer graphs From 8531d739300f9b177e240da82e2a4eea29dddecb Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 11 Jan 2018 14:00:20 +0000 Subject: [PATCH 072/289] Added transaction categories tables --- lib/Pear/LocalLoop/Schema/Result/Category.pm | 40 +++++++++++++++++++ .../LocalLoop/Schema/Result/Transaction.pm | 5 +++ .../Schema/Result/TransactionCategory.pm | 35 ++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 lib/Pear/LocalLoop/Schema/Result/Category.pm create mode 100644 lib/Pear/LocalLoop/Schema/Result/TransactionCategory.pm diff --git a/lib/Pear/LocalLoop/Schema/Result/Category.pm b/lib/Pear/LocalLoop/Schema/Result/Category.pm new file mode 100644 index 0000000..0c1cc66 --- /dev/null +++ b/lib/Pear/LocalLoop/Schema/Result/Category.pm @@ -0,0 +1,40 @@ +package Pear::LocalLoop::Schema::Result::Category; + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +__PACKAGE__->table("category"); + +__PACKAGE__->add_columns( + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, +); + +__PACKAGE__->set_primary_key("id"); + +__PACKAGE__->add_unique_constraint(["name"]); + +__PACKAGE__->has_many( + "transaction_category", + "Pear::LocalLoop::Schema::Result::TransactionCategory", + { "foreign.category_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + +__PACKAGE__->many_to_many( + "transactions", + "transaction_category", + "transaction", +); + +1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm index 32d21c2..b098aa8 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm @@ -71,4 +71,9 @@ __PACKAGE__->belongs_to( { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); +__PACKAGE__->might_have( + "category", + "Pear::LocalLoop::Schema::Result::TransactionCategory" => "transaction_id", +); + 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/TransactionCategory.pm b/lib/Pear/LocalLoop/Schema/Result/TransactionCategory.pm new file mode 100644 index 0000000..0e91891 --- /dev/null +++ b/lib/Pear/LocalLoop/Schema/Result/TransactionCategory.pm @@ -0,0 +1,35 @@ +package Pear::LocalLoop::Schema::Result::TransactionCategory; + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +__PACKAGE__->table("transaction_category"); + +__PACKAGE__->add_columns( + "category_id" => { + data_type => "integer", + is_nullable => 0, + is_foreign_key => 1, + }, + "transaction_id" => { + data_type => 'integer', + is_nullable => 0, + is_foreign_key => 1, + }, +); + +__PACKAGE__->add_unique_constraint(["transaction_id"]); + +__PACKAGE__->belongs_to( + "category", + "Pear::LocalLoop::Schema::Result::Category", + "category_id", +); + +__PACKAGE__->belongs_to( + "transaction", + "Pear::LocalLoop::Schema::Result::Transaction", + "transaction_id", +); From b12cd3fcfc180eff8b40dafb96a8bc4bd9cf7e68 Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 11 Jan 2018 16:23:42 +0000 Subject: [PATCH 073/289] Categories admin interface fully implemented --- lib/Pear/LocalLoop.pm | 6 + .../LocalLoop/Controller/Admin/Categories.pm | 95 + lib/Pear/LocalLoop/Schema.pm | 2 +- .../deploy/20/001-auto-__VERSION.sql | 18 + share/ddl/PostgreSQL/deploy/20/001-auto.sql | 361 ++++ .../ddl/PostgreSQL/upgrade/19-20/001-auto.sql | 34 + .../SQLite/deploy/20/001-auto-__VERSION.sql | 18 + share/ddl/SQLite/deploy/20/001-auto.sql | 250 +++ share/ddl/SQLite/upgrade/19-20/001-auto.sql | 35 + .../_source/deploy/20/001-auto-__VERSION.yml | 91 + share/ddl/_source/deploy/20/001-auto.yml | 1863 +++++++++++++++++ templates/admin/categories/index.html.ep | 30 + templates/admin/categories/read.html.ep | 27 + templates/layouts/admin.html.ep | 10 +- 14 files changed, 2837 insertions(+), 3 deletions(-) create mode 100644 lib/Pear/LocalLoop/Controller/Admin/Categories.pm create mode 100644 share/ddl/PostgreSQL/deploy/20/001-auto-__VERSION.sql create mode 100644 share/ddl/PostgreSQL/deploy/20/001-auto.sql create mode 100644 share/ddl/PostgreSQL/upgrade/19-20/001-auto.sql create mode 100644 share/ddl/SQLite/deploy/20/001-auto-__VERSION.sql create mode 100644 share/ddl/SQLite/deploy/20/001-auto.sql create mode 100644 share/ddl/SQLite/upgrade/19-20/001-auto.sql create mode 100644 share/ddl/_source/deploy/20/001-auto-__VERSION.yml create mode 100644 share/ddl/_source/deploy/20/001-auto.yml create mode 100644 templates/admin/categories/index.html.ep create mode 100644 templates/admin/categories/read.html.ep diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 6ab7fa8..0146d63 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -188,6 +188,12 @@ sub startup { $admin_routes->post('/tokens/:id')->to('admin-tokens#update'); $admin_routes->post('/tokens/:id/delete')->to('admin-tokens#delete'); + $admin_routes->get('/categories')->to('admin-categories#index'); + $admin_routes->post('/categories')->to('admin-categories#create'); + $admin_routes->get('/categories/:id')->to('admin-categories#read'); + $admin_routes->post('/categories/:id')->to('admin-categories#update'); + $admin_routes->post('/categories/:id/delete')->to('admin-categories#delete'); + $admin_routes->get('/users')->to('admin-users#index'); $admin_routes->get('/users/:id')->to('admin-users#read'); $admin_routes->post('/users/:id')->to('admin-users#update'); diff --git a/lib/Pear/LocalLoop/Controller/Admin/Categories.pm b/lib/Pear/LocalLoop/Controller/Admin/Categories.pm new file mode 100644 index 0000000..e0f1eb0 --- /dev/null +++ b/lib/Pear/LocalLoop/Controller/Admin/Categories.pm @@ -0,0 +1,95 @@ +package Pear::LocalLoop::Controller::Admin::Categories; +use Mojo::Base 'Mojolicious::Controller'; + +has result_set => sub { + my $c = shift; + return $c->schema->resultset('Category'); +}; + +sub index { + my $c = shift; + + my $category_rs = $c->result_set; + $category_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); + $c->stash( categories => [ $category_rs->all ] ); +} + +# POST +sub create { + my $c = shift; + + my $validation = $c->validation; + $validation->required('category', 'trim')->like(qr/^[\w]*$/)->not_in_resultset('name', $c->result_set); + + my $category_name = $validation->param('category'); + + if ( $validation->has_error ) { + my $check = shift @{ $c->validation->error('category') }; + if ( $check eq 'required' ) { + $c->flash( error => 'Category name is required' ); + } elsif ( $check eq 'like' ) { + $c->flash( error => 'Category name not valid - Alphanumeric characters and Underscore only' ); + } elsif ( $check eq 'not_in_resultset' ) { + $c->flash( error => 'Category Already Exists' ); + } + } else { + $c->flash( success => 'Category Created' ); + $c->result_set->create({ name => $category_name }); + } + $c->redirect_to( '/admin/categories' ); +} + +# GET +sub read { + my $c = shift; + + my $id = $c->param('id'); + + if ( my $category = $c->result_set->find($id) ) { + $c->stash( category => $category ); + } else { + $c->flash( error => 'No Category found' ); + $c->redirect_to( '/admin/categories' ); + } +} + +# POST +sub update { + my $c = shift; + my $validation = $c->validation; + $validation->required('category', 'trim')->like(qr/^[\w]*$/); + + my $id = $c->param('id'); + + if ( $validation->has_error ) { + my $names = $validation->failed; + $c->flash( error => 'Error in submitted data: ' . join(', ', @$names) ); + $c->redirect_to( '/admin/categories/' . $id ); + } elsif ( my $category = $c->result_set->find($id) ) { + $category->update({ + name => $validation->param('category'), + }); + $c->flash( success => 'Category Updated' ); + $c->redirect_to( '/admin/categories/' . $id ); + } else { + $c->flash( error => 'No Category found' ); + $c->redirect_to( '/admin/categories' ); + } +} + +# DELETE +sub delete { + my $c = shift; + + my $id = $c->param('id'); + + if ( my $category = $c->result_set->find($id) ) { + $category->delete; + $c->flash( success => 'Category Deleted' ); + } else { + $c->flash( error => 'No Category found' ); + } + $c->redirect_to( '/admin/categories' ); +} + +1; diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index 8552b6b..bf363b8 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -6,7 +6,7 @@ use warnings; use base 'DBIx::Class::Schema'; -our $VERSION = 19; +our $VERSION = 20; __PACKAGE__->load_namespaces; diff --git a/share/ddl/PostgreSQL/deploy/20/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/20/001-auto-__VERSION.sql new file mode 100644 index 0000000..7986b78 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/20/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Thu Jan 11 16:18:36 2018 +-- +; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE "dbix_class_deploymenthandler_versions" ( + "id" serial NOT NULL, + "version" character varying(50) NOT NULL, + "ddl" text, + "upgrade_sql" text, + PRIMARY KEY ("id"), + CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version") +); + +; diff --git a/share/ddl/PostgreSQL/deploy/20/001-auto.sql b/share/ddl/PostgreSQL/deploy/20/001-auto.sql new file mode 100644 index 0000000..91c3e35 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/20/001-auto.sql @@ -0,0 +1,361 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Thu Jan 11 16:18:36 2018 +-- +; +-- +-- Table: account_tokens +-- +CREATE TABLE "account_tokens" ( + "id" serial NOT NULL, + "name" text NOT NULL, + "used" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "account_tokens_name" UNIQUE ("name") +); + +; +-- +-- Table: category +-- +CREATE TABLE "category" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "category_name" UNIQUE ("name") +); + +; +-- +-- Table: entities +-- +CREATE TABLE "entities" ( + "id" serial NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: gb_postcodes +-- +CREATE TABLE "gb_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) DEFAULT '' NOT NULL, + "latitude" numeric(7,5), + "longitude" numeric(7,5), + PRIMARY KEY ("outcode", "incode") +); + +; +-- +-- Table: import_sets +-- +CREATE TABLE "import_sets" ( + "id" serial NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: leaderboards +-- +CREATE TABLE "leaderboards" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboards_type" UNIQUE ("type") +); + +; +-- +-- Table: customers +-- +CREATE TABLE "customers" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "display_name" character varying(255) NOT NULL, + "full_name" character varying(255) NOT NULL, + "year_of_birth" integer NOT NULL, + "postcode" character varying(16) NOT NULL, + "latitude" numeric(5,2), + "longitude" numeric(5,2), + PRIMARY KEY ("id") +); +CREATE INDEX "customers_idx_entity_id" on "customers" ("entity_id"); + +; +-- +-- Table: entity_association +-- +CREATE TABLE "entity_association" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "lis" boolean, + "esta" boolean, + PRIMARY KEY ("id") +); +CREATE INDEX "entity_association_idx_entity_id" on "entity_association" ("entity_id"); + +; +-- +-- Table: leaderboard_sets +-- +CREATE TABLE "leaderboard_sets" ( + "id" serial NOT NULL, + "leaderboard_id" integer NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "leaderboard_sets_idx_leaderboard_id" on "leaderboard_sets" ("leaderboard_id"); + +; +-- +-- Table: organisations +-- +CREATE TABLE "organisations" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "street_name" text, + "town" character varying(255) NOT NULL, + "postcode" character varying(16), + "country" character varying(255), + "sector" character varying(1), + "pending" boolean DEFAULT false NOT NULL, + "is_local" boolean, + "is_fair" boolean, + "submitted_by_id" integer, + "latitude" numeric(8,5), + "longitude" numeric(8,5), + PRIMARY KEY ("id") +); +CREATE INDEX "organisations_idx_entity_id" on "organisations" ("entity_id"); + +; +-- +-- Table: transactions +-- +CREATE TABLE "transactions" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "proof_image" text, + "submitted_at" timestamp NOT NULL, + "purchase_time" timestamp NOT NULL, + "distance" numeric(15), + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_idx_buyer_id" on "transactions" ("buyer_id"); +CREATE INDEX "transactions_idx_seller_id" on "transactions" ("seller_id"); + +; +-- +-- Table: users +-- +CREATE TABLE "users" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "email" text NOT NULL, + "join_date" timestamp NOT NULL, + "password" character varying(100) NOT NULL, + "is_admin" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "users_email" UNIQUE ("email") +); +CREATE INDEX "users_idx_entity_id" on "users" ("entity_id"); + +; +-- +-- Table: feedback +-- +CREATE TABLE "feedback" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "feedbacktext" text NOT NULL, + "app_name" character varying(255) NOT NULL, + "package_name" character varying(255) NOT NULL, + "version_code" character varying(255) NOT NULL, + "version_number" character varying(255) NOT NULL, + "actioned" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "feedback_idx_user_id" on "feedback" ("user_id"); + +; +-- +-- Table: import_lookups +-- +CREATE TABLE "import_lookups" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_lookups_idx_entity_id" on "import_lookups" ("entity_id"); +CREATE INDEX "import_lookups_idx_set_id" on "import_lookups" ("set_id"); + +; +-- +-- Table: organisation_payroll +-- +CREATE TABLE "organisation_payroll" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "entry_period" timestamp NOT NULL, + "employee_amount" integer NOT NULL, + "local_employee_amount" integer NOT NULL, + "gross_payroll" numeric(100,0) NOT NULL, + "payroll_income_tax" numeric(100,0) NOT NULL, + "payroll_employee_ni" numeric(100,0) NOT NULL, + "payroll_employer_ni" numeric(100,0) NOT NULL, + "payroll_total_pension" numeric(100,0) NOT NULL, + "payroll_other_benefit" numeric(100,0) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisation_payroll_idx_org_id" on "organisation_payroll" ("org_id"); + +; +-- +-- Table: session_tokens +-- +CREATE TABLE "session_tokens" ( + "id" serial NOT NULL, + "token" character varying(255) NOT NULL, + "user_id" integer NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "session_tokens_token" UNIQUE ("token") +); +CREATE INDEX "session_tokens_idx_user_id" on "session_tokens" ("user_id"); + +; +-- +-- Table: import_values +-- +CREATE TABLE "import_values" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "user_name" character varying(255) NOT NULL, + "purchase_date" timestamp NOT NULL, + "purchase_value" character varying(255) NOT NULL, + "org_name" character varying(255) NOT NULL, + "transaction_id" integer, + "ignore_value" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_values_idx_set_id" on "import_values" ("set_id"); +CREATE INDEX "import_values_idx_transaction_id" on "import_values" ("transaction_id"); + +; +-- +-- Table: leaderboard_values +-- +CREATE TABLE "leaderboard_values" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "set_id" integer NOT NULL, + "position" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "trend" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboard_values_entity_id_set_id" UNIQUE ("entity_id", "set_id") +); +CREATE INDEX "leaderboard_values_idx_entity_id" on "leaderboard_values" ("entity_id"); +CREATE INDEX "leaderboard_values_idx_set_id" on "leaderboard_values" ("set_id"); + +; +-- +-- Table: transaction_category +-- +CREATE TABLE "transaction_category" ( + "category_id" integer NOT NULL, + "transaction_id" integer NOT NULL, + CONSTRAINT "transaction_category_transaction_id" UNIQUE ("transaction_id") +); +CREATE INDEX "transaction_category_idx_category_id" on "transaction_category" ("category_id"); +CREATE INDEX "transaction_category_idx_transaction_id" on "transaction_category" ("transaction_id"); + +; +-- +-- Foreign Key Definitions +-- + +; +ALTER TABLE "customers" ADD CONSTRAINT "customers_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entity_association" ADD CONSTRAINT "entity_association_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "leaderboard_sets" ADD CONSTRAINT "leaderboard_sets_fk_leaderboard_id" FOREIGN KEY ("leaderboard_id") + REFERENCES "leaderboards" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "users" ADD CONSTRAINT "users_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "feedback" ADD CONSTRAINT "feedback_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisation_payroll" ADD CONSTRAINT "organisation_payroll_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") DEFERRABLE; + +; +ALTER TABLE "session_tokens" ADD CONSTRAINT "session_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "leaderboard_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; diff --git a/share/ddl/PostgreSQL/upgrade/19-20/001-auto.sql b/share/ddl/PostgreSQL/upgrade/19-20/001-auto.sql new file mode 100644 index 0000000..184a61f --- /dev/null +++ b/share/ddl/PostgreSQL/upgrade/19-20/001-auto.sql @@ -0,0 +1,34 @@ +-- Convert schema 'share/ddl/_source/deploy/19/001-auto.yml' to 'share/ddl/_source/deploy/20/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE "category" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "category_name" UNIQUE ("name") +); + +; +CREATE TABLE "transaction_category" ( + "category_id" integer NOT NULL, + "transaction_id" integer NOT NULL, + CONSTRAINT "transaction_category_transaction_id" UNIQUE ("transaction_id") +); +CREATE INDEX "transaction_category_idx_category_id" on "transaction_category" ("category_id"); +CREATE INDEX "transaction_category_idx_transaction_id" on "transaction_category" ("transaction_id"); + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; + +COMMIT; + diff --git a/share/ddl/SQLite/deploy/20/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/20/001-auto-__VERSION.sql new file mode 100644 index 0000000..8dfa2a9 --- /dev/null +++ b/share/ddl/SQLite/deploy/20/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Thu Jan 11 16:18:36 2018 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE dbix_class_deploymenthandler_versions ( + id INTEGER PRIMARY KEY NOT NULL, + version varchar(50) NOT NULL, + ddl text, + upgrade_sql text +); +CREATE UNIQUE INDEX dbix_class_deploymenthandler_versions_version ON dbix_class_deploymenthandler_versions (version); +COMMIT; diff --git a/share/ddl/SQLite/deploy/20/001-auto.sql b/share/ddl/SQLite/deploy/20/001-auto.sql new file mode 100644 index 0000000..f80e7ca --- /dev/null +++ b/share/ddl/SQLite/deploy/20/001-auto.sql @@ -0,0 +1,250 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Thu Jan 11 16:18:36 2018 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: account_tokens +-- +CREATE TABLE account_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + name text NOT NULL, + used integer NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX account_tokens_name ON account_tokens (name); +-- +-- Table: category +-- +CREATE TABLE category ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX category_name ON category (name); +-- +-- Table: entities +-- +CREATE TABLE entities ( + id INTEGER PRIMARY KEY NOT NULL, + type varchar(255) NOT NULL +); +-- +-- Table: gb_postcodes +-- +CREATE TABLE gb_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL DEFAULT '', + latitude decimal(7,5), + longitude decimal(7,5), + PRIMARY KEY (outcode, incode) +); +-- +-- Table: import_sets +-- +CREATE TABLE import_sets ( + id INTEGER PRIMARY KEY NOT NULL, + date datetime NOT NULL +); +-- +-- Table: leaderboards +-- +CREATE TABLE leaderboards ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + type varchar(255) NOT NULL +); +CREATE UNIQUE INDEX leaderboards_type ON leaderboards (type); +-- +-- Table: customers +-- +CREATE TABLE customers ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + display_name varchar(255) NOT NULL, + full_name varchar(255) NOT NULL, + year_of_birth integer NOT NULL, + postcode varchar(16) NOT NULL, + latitude decimal(5,2), + longitude decimal(5,2), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX customers_idx_entity_id ON customers (entity_id); +-- +-- Table: entity_association +-- +CREATE TABLE entity_association ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + lis boolean, + esta boolean, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX entity_association_idx_entity_id ON entity_association (entity_id); +-- +-- Table: leaderboard_sets +-- +CREATE TABLE leaderboard_sets ( + id INTEGER PRIMARY KEY NOT NULL, + leaderboard_id integer NOT NULL, + date datetime NOT NULL, + FOREIGN KEY (leaderboard_id) REFERENCES leaderboards(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_sets_idx_leaderboard_id ON leaderboard_sets (leaderboard_id); +-- +-- Table: organisations +-- +CREATE TABLE organisations ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + name varchar(255) NOT NULL, + street_name text, + town varchar(255) NOT NULL, + postcode varchar(16), + country varchar(255), + sector varchar(1), + pending boolean NOT NULL DEFAULT false, + is_local boolean, + is_fair boolean, + submitted_by_id integer, + latitude decimal(8,5), + longitude decimal(8,5), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX organisations_idx_entity_id ON organisations (entity_id); +-- +-- Table: transactions +-- +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + distance numeric(15), + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transactions_idx_buyer_id ON transactions (buyer_id); +CREATE INDEX transactions_idx_seller_id ON transactions (seller_id); +-- +-- Table: users +-- +CREATE TABLE users ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + email text NOT NULL, + join_date datetime NOT NULL, + password varchar(100) NOT NULL, + is_admin boolean NOT NULL DEFAULT false, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX users_idx_entity_id ON users (entity_id); +CREATE UNIQUE INDEX users_email ON users (email); +-- +-- Table: feedback +-- +CREATE TABLE feedback ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + submitted_at datetime NOT NULL, + feedbacktext text NOT NULL, + app_name varchar(255) NOT NULL, + package_name varchar(255) NOT NULL, + version_code varchar(255) NOT NULL, + version_number varchar(255) NOT NULL, + actioned boolean NOT NULL DEFAULT false, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX feedback_idx_user_id ON feedback (user_id); +-- +-- Table: import_lookups +-- +CREATE TABLE import_lookups ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + name varchar(255) NOT NULL, + entity_id integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_lookups_idx_entity_id ON import_lookups (entity_id); +CREATE INDEX import_lookups_idx_set_id ON import_lookups (set_id); +-- +-- Table: organisation_payroll +-- +CREATE TABLE organisation_payroll ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + submitted_at datetime NOT NULL, + entry_period datetime NOT NULL, + employee_amount integer NOT NULL, + local_employee_amount integer NOT NULL, + gross_payroll numeric(100,0) NOT NULL, + payroll_income_tax numeric(100,0) NOT NULL, + payroll_employee_ni numeric(100,0) NOT NULL, + payroll_employer_ni numeric(100,0) NOT NULL, + payroll_total_pension numeric(100,0) NOT NULL, + payroll_other_benefit numeric(100,0) NOT NULL, + FOREIGN KEY (org_id) REFERENCES organisations(id) +); +CREATE INDEX organisation_payroll_idx_org_id ON organisation_payroll (org_id); +-- +-- Table: session_tokens +-- +CREATE TABLE session_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + token varchar(255) NOT NULL, + user_id integer NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX session_tokens_idx_user_id ON session_tokens (user_id); +CREATE UNIQUE INDEX session_tokens_token ON session_tokens (token); +-- +-- Table: import_values +-- +CREATE TABLE import_values ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + user_name varchar(255) NOT NULL, + purchase_date datetime NOT NULL, + purchase_value varchar(255) NOT NULL, + org_name varchar(255) NOT NULL, + transaction_id integer, + ignore_value boolean NOT NULL DEFAULT false, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_values_idx_set_id ON import_values (set_id); +CREATE INDEX import_values_idx_transaction_id ON import_values (transaction_id); +-- +-- Table: leaderboard_values +-- +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_values_idx_entity_id ON leaderboard_values (entity_id); +CREATE INDEX leaderboard_values_idx_set_id ON leaderboard_values (set_id); +CREATE UNIQUE INDEX leaderboard_values_entity_id_set_id ON leaderboard_values (entity_id, set_id); +-- +-- Table: transaction_category +-- +CREATE TABLE transaction_category ( + category_id integer NOT NULL, + transaction_id integer NOT NULL, + FOREIGN KEY (category_id) REFERENCES category(id), + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); +CREATE INDEX transaction_category_idx_category_id ON transaction_category (category_id); +CREATE INDEX transaction_category_idx_transaction_id ON transaction_category (transaction_id); +CREATE UNIQUE INDEX transaction_category_transaction_id ON transaction_category (transaction_id); +COMMIT; diff --git a/share/ddl/SQLite/upgrade/19-20/001-auto.sql b/share/ddl/SQLite/upgrade/19-20/001-auto.sql new file mode 100644 index 0000000..7f2e444 --- /dev/null +++ b/share/ddl/SQLite/upgrade/19-20/001-auto.sql @@ -0,0 +1,35 @@ +-- Convert schema 'share/ddl/_source/deploy/19/001-auto.yml' to 'share/ddl/_source/deploy/20/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE category ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL +); + +; +CREATE UNIQUE INDEX category_name ON category (name); + +; +CREATE TABLE transaction_category ( + category_id integer NOT NULL, + transaction_id integer NOT NULL, + FOREIGN KEY (category_id) REFERENCES category(id), + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); + +; +CREATE INDEX transaction_category_idx_category_id ON transaction_category (category_id); + +; +CREATE INDEX transaction_category_idx_transaction_id ON transaction_category (transaction_id); + +; +CREATE UNIQUE INDEX transaction_category_transaction_id ON transaction_category (transaction_id); + +; + +COMMIT; + diff --git a/share/ddl/_source/deploy/20/001-auto-__VERSION.yml b/share/ddl/_source/deploy/20/001-auto-__VERSION.yml new file mode 100644 index 0000000..907f443 --- /dev/null +++ b/share/ddl/_source/deploy/20/001-auto-__VERSION.yml @@ -0,0 +1,91 @@ +--- +schema: + procedures: {} + tables: + dbix_class_deploymenthandler_versions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - version + match_type: '' + name: dbix_class_deploymenthandler_versions_version + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + ddl: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ddl + order: 3 + size: + - 0 + id: + data_type: int + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + upgrade_sql: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: upgrade_sql + order: 4 + size: + - 0 + version: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: version + order: 2 + size: + - 50 + indices: [] + name: dbix_class_deploymenthandler_versions + options: [] + order: 1 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - __VERSION + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 diff --git a/share/ddl/_source/deploy/20/001-auto.yml b/share/ddl/_source/deploy/20/001-auto.yml new file mode 100644 index 0000000..f9980a3 --- /dev/null +++ b/share/ddl/_source/deploy/20/001-auto.yml @@ -0,0 +1,1863 @@ +--- +schema: + procedures: {} + tables: + account_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: account_tokens_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 0 + used: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: used + order: 3 + size: + - 0 + indices: [] + name: account_tokens + options: [] + order: 1 + category: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: category_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 255 + indices: [] + name: category + options: [] + order: 2 + customers: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: customers_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + display_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: display_name + order: 3 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + full_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 4 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 7 + size: + - 5 + - 2 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 8 + size: + - 5 + - 2 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + year_of_birth: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: year_of_birth + order: 5 + size: + - 0 + indices: + - fields: + - entity_id + name: customers_idx_entity_id + options: [] + type: NORMAL + name: customers + options: [] + order: 7 + entities: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: type + order: 2 + size: + - 255 + indices: [] + name: entities + options: [] + order: 3 + entity_association: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entity_association_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + esta: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: esta + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + lis: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: lis + order: 3 + size: + - 0 + indices: + - fields: + - entity_id + name: entity_association_idx_entity_id + options: [] + type: NORMAL + name: entity_association + options: [] + order: 8 + feedback: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: feedback_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + actioned: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: actioned + order: 9 + size: + - 0 + app_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: app_name + order: 5 + size: + - 255 + feedbacktext: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: feedbacktext + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + package_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: package_name + order: 6 + size: + - 255 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + version_code: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_code + order: 7 + size: + - 255 + version_number: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_number + order: 8 + size: + - 255 + indices: + - fields: + - user_id + name: feedback_idx_user_id + options: [] + type: NORMAL + name: feedback + options: [] + order: 13 + gb_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + incode: + data_type: char + default_value: '' + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 3 + size: + - 7 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 4 + size: + - 7 + - 5 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + indices: [] + name: gb_postcodes + options: [] + order: 4 + import_lookups: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: import_lookups_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_lookups_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + indices: + - fields: + - entity_id + name: import_lookups_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: import_lookups_idx_set_id + options: [] + type: NORMAL + name: import_lookups + options: [] + order: 14 + import_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: import_sets + options: [] + order: 5 + import_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: import_values_fk_transaction_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ignore_value: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ignore_value + order: 8 + size: + - 0 + org_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_name + order: 6 + size: + - 255 + purchase_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_date + order: 4 + size: + - 0 + purchase_value: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_value + order: 5 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 7 + size: + - 0 + user_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_name + order: 3 + size: + - 255 + indices: + - fields: + - set_id + name: import_values_idx_set_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: import_values_idx_transaction_id + options: [] + type: NORMAL + name: import_values + options: [] + order: 17 + leaderboard_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - leaderboard_id + match_type: '' + name: leaderboard_sets_fk_leaderboard_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboards + type: FOREIGN KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + leaderboard_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: leaderboard_id + order: 2 + size: + - 0 + indices: + - fields: + - leaderboard_id + name: leaderboard_sets_idx_leaderboard_id + options: [] + type: NORMAL + name: leaderboard_sets + options: [] + order: 9 + leaderboard_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + - set_id + match_type: '' + name: leaderboard_values_entity_id_set_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - entity_id + match_type: '' + name: leaderboard_values_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: leaderboard_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboard_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + position: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: position + order: 4 + size: + - 0 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: set_id + order: 3 + size: + - 0 + trend: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: trend + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 5 + size: + - 100 + - 0 + indices: + - fields: + - entity_id + name: leaderboard_values_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: leaderboard_values_idx_set_id + options: [] + type: NORMAL + name: leaderboard_values + options: [] + order: 18 + leaderboards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - type + match_type: '' + name: leaderboards_type + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 255 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: type + order: 3 + size: + - 255 + indices: [] + name: leaderboards + options: [] + order: 6 + organisation_payroll: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisation_payroll_fk_org_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: employee_amount + order: 5 + size: + - 0 + entry_period: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entry_period + order: 4 + size: + - 0 + gross_payroll: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_payroll + order: 7 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_employee_amount + order: 6 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + payroll_employee_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employee_ni + order: 9 + size: + - 100 + - 0 + payroll_employer_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employer_ni + order: 10 + size: + - 100 + - 0 + payroll_income_tax: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_income_tax + order: 8 + size: + - 100 + - 0 + payroll_other_benefit: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_other_benefit + order: 12 + size: + - 100 + - 0 + payroll_total_pension: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_total_pension + order: 11 + size: + - 100 + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + indices: + - fields: + - org_id + name: organisation_payroll_idx_org_id + options: [] + type: NORMAL + name: organisation_payroll + options: [] + order: 15 + organisations: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: organisations_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + country: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: country + order: 7 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_fair: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_fair + order: 11 + size: + - 0 + is_local: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_local + order: 10 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 13 + size: + - 8 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 14 + size: + - 8 + - 5 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + pending: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: pending + order: 9 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + sector: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: sector + order: 8 + size: + - 1 + street_name: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: street_name + order: 4 + size: + - 0 + submitted_by_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: submitted_by_id + order: 12 + size: + - 0 + town: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: town + order: 5 + size: + - 255 + indices: + - fields: + - entity_id + name: organisations_idx_entity_id + options: [] + type: NORMAL + name: organisations + options: [] + order: 10 + session_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - token + match_type: '' + name: session_tokens_token + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: session_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: token + order: 2 + size: + - 255 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 3 + size: + - 0 + indices: + - fields: + - user_id + name: session_tokens_idx_user_id + options: [] + type: NORMAL + name: session_tokens + options: [] + order: 16 + transaction_category: + constraints: + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_transaction_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - category_id + match_type: '' + name: transaction_category_fk_category_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: category + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_fk_transaction_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + category_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: category_id + order: 1 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - category_id + name: transaction_category_idx_category_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: transaction_category_idx_transaction_id + options: [] + type: NORMAL + name: transaction_category + options: [] + order: 19 + transactions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transactions_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transactions_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 8 + size: + - 15 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + proof_image: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: proof_image + order: 5 + size: + - 0 + purchase_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_time + order: 7 + size: + - 0 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transactions_idx_buyer_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transactions_idx_seller_id + options: [] + type: NORMAL + name: transactions + options: [] + order: 11 + users: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: users_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: users_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 3 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_admin: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_admin + order: 6 + size: + - 0 + join_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: join_date + order: 4 + size: + - 0 + password: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: password + order: 5 + size: + - 100 + indices: + - fields: + - entity_id + name: users_idx_entity_id + options: [] + type: NORMAL + name: users + options: [] + order: 12 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - AccountToken + - Category + - Customer + - Entity + - EntityAssociation + - Feedback + - GbPostcode + - ImportLookup + - ImportSet + - ImportValue + - Leaderboard + - LeaderboardSet + - LeaderboardValue + - Organisation + - OrganisationPayroll + - SessionToken + - Transaction + - TransactionCategory + - User + - ViewQuantisedTransactionPg + - ViewQuantisedTransactionSQLite + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 diff --git a/templates/admin/categories/index.html.ep b/templates/admin/categories/index.html.ep new file mode 100644 index 0000000..a4e528a --- /dev/null +++ b/templates/admin/categories/index.html.ep @@ -0,0 +1,30 @@ +% layout 'admin'; +% title 'Categories'; +% content_for javascript => begin +% end +% if ( my $error = flash 'error' ) { + +% } elsif ( my $success = flash 'success' ) { + +% } +
+
+
+ + + + +
+
+
+
+ % for my $category (@$categories) { + + <%= $category->{name} %> + + % } +
diff --git a/templates/admin/categories/read.html.ep b/templates/admin/categories/read.html.ep new file mode 100644 index 0000000..2cf8af0 --- /dev/null +++ b/templates/admin/categories/read.html.ep @@ -0,0 +1,27 @@ +% layout 'admin'; +% title 'Categories'; +% content_for javascript => begin +% end +% if ( my $error = flash 'error' ) { + +% } elsif ( my $success = flash 'success' ) { + +% } +
+
+ + +
+
+ +
+
+
+
+ +
+
diff --git a/templates/layouts/admin.html.ep b/templates/layouts/admin.html.ep index c546b04..4e2405c 100644 --- a/templates/layouts/admin.html.ep +++ b/templates/layouts/admin.html.ep @@ -41,8 +41,14 @@ - + @@ -66,6 +74,19 @@
+ % if ( my $f_error = flash 'error' ) { + + % } elsif ( my $s_error = stash 'error' ) { + + % } elsif ( my $success = flash 'success' ) { + + % } <%= content %>
- - - - + + + + %= content_for 'javascript'; diff --git a/templates/layouts/admin_errors.html.ep b/templates/layouts/admin_errors.html.ep deleted file mode 100644 index 808a5b9..0000000 --- a/templates/layouts/admin_errors.html.ep +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - LocalLoop Admin - <%= title %> - - - - - - %= stylesheet '/static/admin/css/main.css'; - - -
- -
- % if ( my $f_error = flash 'error' ) { - - % } elsif ( my $s_error = stash 'error' ) { - - % } elsif ( my $success = flash 'success' ) { - - % } - <%= content %> -
- - - - - - %= content_for 'javascript'; - - diff --git a/templates/root/index.html.ep b/templates/root/index.html.ep index 9a2d6e4..c529771 100644 --- a/templates/root/index.html.ep +++ b/templates/root/index.html.ep @@ -4,5 +4,7 @@ %= javascript '/static/user/js/home.js'; % end
-

App currently in development, please come back later!

+

Local Loop API Server

+

If you have arrived here, you're either a developer or something has gone wrong! Oops!

+ Go to Admin Login
From 0332b8bdb2d99cd5cefc7a01e9c558fa90346258 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 9 Sep 2019 16:24:07 +0100 Subject: [PATCH 228/289] Added type name filter to show data better on frontend --- lib/Pear/LocalLoop/Controller/Api/External.pm | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/External.pm b/lib/Pear/LocalLoop/Controller/Api/External.pm index 43a3087..97d2274 100644 --- a/lib/Pear/LocalLoop/Controller/Api/External.pm +++ b/lib/Pear/LocalLoop/Controller/Api/External.pm @@ -402,6 +402,16 @@ sub post_lcc_table_summary { my $transaction_type_data = {}; + my %meta_names = ( + local_service => "Local Services", + regional_service => "Regional Services", + national_service => "National Services", + private_household_rebate => "Private Household Rebates etc", + business_tax_and_rebate => "Business Tax & Service Rebates", + stat_loc_gov => "Statutory Loc Gov", + central_loc_gov => "Central Gov HMRC", + ); + for my $meta ( qw/ local_service regional_service @@ -431,7 +441,12 @@ sub post_lcc_table_summary { ( $transaction_type_rs ? ( count => $transaction_type_rs->get_column('count'), sum => $transaction_type_rs->get_column('sum'), - ) : () ), + type => $meta_names{$meta}, + ) : ( + count => 0, + sum => 0, + type => $meta_names{$meta}, + ) ), } } From 93191c10d2ea782b6e2ac4aad4fc65f6ea0a2b99 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Mon, 9 Sep 2019 16:42:49 +0100 Subject: [PATCH 229/289] fix transaction list in admin and speed up external count --- lib/Pear/LocalLoop/Controller/Admin/Transactions.pm | 4 ++-- lib/Pear/LocalLoop/Controller/Api/External.pm | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm index c73697f..514f326 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm @@ -18,8 +18,8 @@ sub index { {}, { select => [ - { count => 'id', '-as' => 'count' }, - { sum => 'value', '-as' => 'sum_value' }, + { count => 'me.value', '-as' => 'count' }, + { sum => 'me.value', '-as' => 'sum_value' }, 'quantised_weeks', ], group_by => 'quantised_weeks', diff --git a/lib/Pear/LocalLoop/Controller/Api/External.pm b/lib/Pear/LocalLoop/Controller/Api/External.pm index a33c5f2..269d461 100644 --- a/lib/Pear/LocalLoop/Controller/Api/External.pm +++ b/lib/Pear/LocalLoop/Controller/Api/External.pm @@ -199,14 +199,15 @@ sub post_supplier_count { buyer_id => $user->entity->id, }, { - prefetch => { 'seller' => 'organisation' }, + join => { 'seller' => 'organisation' }, select => [ { count => 'me.id', '-as' => 'count' }, { sum => 'me.value', '-as' => 'total_spend' }, 'organisation.name', 'me.quantised_days', ], - group_by => [ 'me.quantised_days', 'seller.id' ], + as => [ qw/ count total_spend name quantised_days / ], + group_by => [ qw/ me.quantised_days seller.id organisation.id / ], order_by => { '-asc' => 'me.quantised_days' }, } ); @@ -216,7 +217,7 @@ sub post_supplier_count { count => $_->get_column('count'), value => ($_->get_column('total_spend') / 100000) // 0, date => $_->get_column('quantised_days'), - seller => $_->seller->organisation->name, + seller => $_->get_column('name'), }} $spend_rs->all, ); From cd8204a759c0b0149b5ba32a853638e9c9788439 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Mon, 9 Sep 2019 16:44:05 +0100 Subject: [PATCH 230/289] oops still using wrong column name --- lib/Pear/LocalLoop/Controller/Api/External.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/External.pm b/lib/Pear/LocalLoop/Controller/Api/External.pm index 269d461..1fa47fb 100644 --- a/lib/Pear/LocalLoop/Controller/Api/External.pm +++ b/lib/Pear/LocalLoop/Controller/Api/External.pm @@ -201,7 +201,7 @@ sub post_supplier_count { { join => { 'seller' => 'organisation' }, select => [ - { count => 'me.id', '-as' => 'count' }, + { count => 'me.value', '-as' => 'count' }, { sum => 'me.value', '-as' => 'total_spend' }, 'organisation.name', 'me.quantised_days', From f7b4fd251e0944177b02760f800e44daf876d31d Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Mon, 9 Sep 2019 18:03:08 +0100 Subject: [PATCH 231/289] added search on supplier listings --- README.md | 10 ++++++++++ lib/Pear/LocalLoop/Controller/Api/External.pm | 7 +++++++ .../Result/ViewQuantisedTransactionSQLite.pm | 14 ++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/README.md b/README.md index 513afa1..ab883ed 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,16 @@ To import ward data, get the ward data csv and then run the following command: --args '[ "/path/to/ward/csv" ]' ``` +# Setting up Entity Postcodes + +Assuming you have imported codepoint open, then to properly assign all + postcodes: + +```shell script +./script/pear-local_loop minion job \ + --enqueue entity_postcode_lookup +``` + ## Example PostgreSQL setup ``` diff --git a/lib/Pear/LocalLoop/Controller/Api/External.pm b/lib/Pear/LocalLoop/Controller/Api/External.pm index 9c92a71..72eee9b 100644 --- a/lib/Pear/LocalLoop/Controller/Api/External.pm +++ b/lib/Pear/LocalLoop/Controller/Api/External.pm @@ -64,6 +64,7 @@ sub post_lcc_suppliers { $v->optional('page')->number; $v->optional('sort_by'); $v->optional('sort_dir'); + $v->optional('search'); my $order_by = [ { -asc => 'organisation.name' }, @@ -85,6 +86,12 @@ sub post_lcc_suppliers { my $lcc_suppliers = $c->schema->resultset('Entity')->search( { 'sales.buyer_id' => $user->entity->id, + ( $v->param('search') ? ( + '-or' => [ + { 'organisation.name' => { 'like' => $v->param('search') . '%' } }, + { 'organisation.postcode' => { 'like' => $v->param('search') . '%' } }, + ] + ) : () ), }, { join => [ 'sales', 'organisation' ], diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm index 6b5b503..fc38ba2 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm @@ -23,4 +23,18 @@ SELECT "value", FROM "transactions" /); +__PACKAGE__->belongs_to( + "buyer", + "Pear::LocalLoop::Schema::Result::Entity", + { id => "buyer_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, +); + +__PACKAGE__->belongs_to( + "seller", + "Pear::LocalLoop::Schema::Result::Entity", + { id => "seller_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, +); + 1; From e3a3c1cc917aa0c200246181cec4e287f9a8b277 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Mon, 9 Sep 2019 19:32:14 +0100 Subject: [PATCH 232/289] filter everything by date --- lib/Pear/LocalLoop/Controller/Api/External.pm | 131 +++++++++++------- 1 file changed, 80 insertions(+), 51 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/External.pm b/lib/Pear/LocalLoop/Controller/Api/External.pm index 72eee9b..baa7149 100644 --- a/lib/Pear/LocalLoop/Controller/Api/External.pm +++ b/lib/Pear/LocalLoop/Controller/Api/External.pm @@ -86,12 +86,12 @@ sub post_lcc_suppliers { my $lcc_suppliers = $c->schema->resultset('Entity')->search( { 'sales.buyer_id' => $user->entity->id, - ( $v->param('search') ? ( + ($v->param('search') ? ( '-or' => [ { 'organisation.name' => { 'like' => $v->param('search') . '%' } }, { 'organisation.postcode' => { 'like' => $v->param('search') . '%' } }, ] - ) : () ), + ) : ()), }, { join => [ 'sales', 'organisation' ], @@ -133,13 +133,15 @@ sub post_year_spend { my $user = $c->stash->{api_user}; - # Temporary date lock for dev data - my $last = DateTime->new( - year => 2019, - month => 4, - day => 1 - ); - my $first = $last->clone->subtract(years => 1); + my $v = $c->validation; + $v->input($c->stash->{api_json}); + $v->required('from'); + $v->required('to'); + + return $c->api_validation_error if $v->has_error; + + my $last = $c->parse_iso_datetime($v->param('to')); + my $first = $c->parse_iso_datetime($v->param('from')); my $dtf = $c->schema->storage->datetime_parser; my $driver = $c->schema->storage->dbh->{Driver}->{Name}; @@ -185,13 +187,15 @@ sub post_supplier_count { my $user = $c->stash->{api_user}; - # Temporary date lock for dev data - my $last = DateTime->new( - year => 2019, - month => 4, - day => 1 - ); - my $first = $last->clone->subtract(years => 1); + my $v = $c->validation; + $v->input($c->stash->{api_json}); + $v->required('from'); + $v->required('to'); + + return $c->api_validation_error if $v->has_error; + + my $last = $c->parse_iso_datetime($v->param('to')); + my $first = $c->parse_iso_datetime($v->param('from')); my $dtf = $c->schema->storage->datetime_parser; my $driver = $c->schema->storage->dbh->{Driver}->{Name}; @@ -206,15 +210,15 @@ sub post_supplier_count { buyer_id => $user->entity->id, }, { - join => { 'seller' => 'organisation' }, - select => [ + join => { 'seller' => 'organisation' }, + select => [ { count => 'me.value', '-as' => 'count' }, { sum => 'me.value', '-as' => 'total_spend' }, 'organisation.name', 'me.quantised_days', ], - as => [ qw/ count total_spend name quantised_days / ], - group_by => [ qw/ me.quantised_days seller.id organisation.id / ], + as => [ qw/count total_spend name quantised_days/ ], + group_by => [ qw/me.quantised_days seller.id organisation.id/ ], order_by => { '-asc' => 'me.quantised_days' }, } ); @@ -374,37 +378,56 @@ sub post_supplier_history { sub post_lcc_table_summary { my $c = shift; - my $validation = $c->validation; - $validation->input($c->stash->{api_json}); + my $user = $c->stash->{api_user}; + + my $v = $c->validation; + $v->input($c->stash->{api_json}); + $v->required('from'); + $v->required('to'); + + return $c->api_validation_error if $v->has_error; + + my $last = $c->parse_iso_datetime($v->param('to')); + my $first = $c->parse_iso_datetime($v->param('from')); my $transaction_rs = $c->schema->resultset('Transaction'); - my $ward_transactions_rs = $transaction_rs->search({}, + my $dtf = $c->schema->storage->datetime_parser; + my $ward_transactions_rs = $transaction_rs->search( { - join => { seller => { postcode => { gb_postcode => 'ward' } } }, + purchase_time => { + -between => [ + $dtf->format_datetime($first), + $dtf->format_datetime($last), + ], + buyer_id => $user->entity->id, + }, + }, + { + join => { seller => { postcode => { gb_postcode => 'ward' } } }, group_by => 'ward.id', - select => [ + select => [ { count => 'me.id', '-as' => 'count' }, { sum => 'me.value', '-as' => 'sum' }, 'ward.ward' ], - as => [ qw/ count sum ward_name /], + as => [ qw/count sum ward_name/ ], } ); my $transaction_type_data = {}; my %meta_names = ( - local_service => "Local Services", - regional_service => "Regional Services", - national_service => "National Services", + local_service => "Local Services", + regional_service => "Regional Services", + national_service => "National Services", private_household_rebate => "Private Household Rebates etc", - business_tax_and_rebate => "Business Tax & Service Rebates", - stat_loc_gov => "Statutory Loc Gov", - central_loc_gov => "Central Gov HMRC", + business_tax_and_rebate => "Business Tax & Service Rebates", + stat_loc_gov => "Statutory Loc Gov", + central_loc_gov => "Central Gov HMRC", ); - for my $meta ( qw/ + for my $meta (qw/ local_service regional_service national_service @@ -412,48 +435,54 @@ sub post_lcc_table_summary { business_tax_and_rebate stat_loc_gov central_loc_gov - / ) { + /) { my $transaction_type_rs = $transaction_rs->search( { - 'meta.'.$meta => 1, + 'me.purchase_time' => { + -between => [ + $dtf->format_datetime($first), + $dtf->format_datetime($last), + ], + }, + 'me.buyer_id' => $user->entity->id, + 'meta.' . $meta => 1, }, { - join => 'meta', + join => 'meta', group_by => 'meta.' . $meta, - select => [ + select => [ { count => 'me.id', '-as' => 'count' }, { sum => 'me.value', '-as' => 'sum' }, ], - as => [ qw/ count sum /], + as => [ qw/count sum/ ], } )->first; - $transaction_type_data->{$meta} = { - ( $transaction_type_rs ? ( + ($transaction_type_rs ? ( count => $transaction_type_rs->get_column('count'), - sum => $transaction_type_rs->get_column('sum'), - type => $meta_names{$meta}, - ) : ( + sum => $transaction_type_rs->get_column('sum'), + type => $meta_names{$meta}, + ) : ( count => 0, - sum => 0, - type => $meta_names{$meta}, - ) ), + sum => 0, + type => $meta_names{$meta}, + )), } } my @ward_transaction_list = ( map {{ - ward => $_->get_column('ward_name') || "N/A", - sum => $_->get_column('sum') / 100000, + ward => $_->get_column('ward_name') || "N/A", + sum => $_->get_column('sum') / 100000, count => $_->get_column('count'), }} $ward_transactions_rs->all ); - return $c->render( json => { + return $c->render(json => { success => Mojo::JSON->true, - wards => \@ward_transaction_list, - types => $transaction_type_data, + wards => \@ward_transaction_list, + types => $transaction_type_data, }); } From 19b453081091a13907e14f8030810177fb397343 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Mon, 9 Sep 2019 19:48:16 +0100 Subject: [PATCH 233/289] fix a few bugs, oops --- lib/Pear/LocalLoop/Controller/Api/External.pm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/External.pm b/lib/Pear/LocalLoop/Controller/Api/External.pm index baa7149..6167f81 100644 --- a/lib/Pear/LocalLoop/Controller/Api/External.pm +++ b/lib/Pear/LocalLoop/Controller/Api/External.pm @@ -140,8 +140,8 @@ sub post_year_spend { return $c->api_validation_error if $v->has_error; - my $last = $c->parse_iso_datetime($v->param('to')); - my $first = $c->parse_iso_datetime($v->param('from')); + my $last = $c->parse_iso_date($v->param('to')); + my $first = $c->parse_iso_date($v->param('from')); my $dtf = $c->schema->storage->datetime_parser; my $driver = $c->schema->storage->dbh->{Driver}->{Name}; @@ -194,8 +194,8 @@ sub post_supplier_count { return $c->api_validation_error if $v->has_error; - my $last = $c->parse_iso_datetime($v->param('to')); - my $first = $c->parse_iso_datetime($v->param('from')); + my $last = $c->parse_iso_date($v->param('to')); + my $first = $c->parse_iso_date($v->param('from')); my $dtf = $c->schema->storage->datetime_parser; my $driver = $c->schema->storage->dbh->{Driver}->{Name}; @@ -387,8 +387,8 @@ sub post_lcc_table_summary { return $c->api_validation_error if $v->has_error; - my $last = $c->parse_iso_datetime($v->param('to')); - my $first = $c->parse_iso_datetime($v->param('from')); + my $last = $c->parse_iso_date($v->param('to')); + my $first = $c->parse_iso_date($v->param('from')); my $transaction_rs = $c->schema->resultset('Transaction'); @@ -400,8 +400,8 @@ sub post_lcc_table_summary { $dtf->format_datetime($first), $dtf->format_datetime($last), ], - buyer_id => $user->entity->id, }, + buyer_id => $user->entity->id, }, { join => { seller => { postcode => { gb_postcode => 'ward' } } }, From b3139c3bf013b1e564335210e867055ce455c49c Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Tue, 10 Sep 2019 09:29:17 +0100 Subject: [PATCH 234/289] reduce memory usage importing CSV files --- lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm | 4 +--- lib/Pear/LocalLoop/Import/Role/CSV.pm | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm index c1efb5f..4068e01 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm @@ -15,9 +15,7 @@ has '+csv_required_columns' => ( sub import_csv { my ($self) = @_; - my $rows = $self->csv_data; - - foreach my $row ( @{$rows} ) { + while ( my $row = $self->get_csv_line ) { $self->_row_to_result($row); } } diff --git a/lib/Pear/LocalLoop/Import/Role/CSV.pm b/lib/Pear/LocalLoop/Import/Role/CSV.pm index 110252f..954d986 100644 --- a/lib/Pear/LocalLoop/Import/Role/CSV.pm +++ b/lib/Pear/LocalLoop/Import/Role/CSV.pm @@ -67,6 +67,11 @@ has csv_data => ( } ); +sub get_csv_line { + my $self = shift; + return $self->_text_csv->getline_hr( $self->_csv_filehandle ); +} + sub check_headers { my $self = shift; my $req_headers = $self->csv_required_columns; From 1075f59086ec81d4247fc7788748dcac0d0b5607 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Tue, 10 Sep 2019 09:32:15 +0100 Subject: [PATCH 235/289] need to check headers first --- lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm index 4068e01..fc01288 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm @@ -15,6 +15,8 @@ has '+csv_required_columns' => ( sub import_csv { my ($self) = @_; + $self->check_headers; + while ( my $row = $self->get_csv_line ) { $self->_row_to_result($row); } From c9e272e3801d313ce502711fe67c21636b416b5e Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 11 Sep 2019 14:19:12 +0100 Subject: [PATCH 236/289] made changes to CSV import to improve memory usage uses same mechanism as postcode import code change does --- lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm | 4 ++-- lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm index 678c6c5..c191534 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm @@ -13,9 +13,9 @@ has '+csv_required_columns' => ( sub import_csv { my ($self) = @_; - my $rows = $self->csv_data; + $self->check_headers; - foreach my $row ( @{$rows} ) { + while ( my $row = $self->get_csv_line ) { $self->_row_to_result($row); } } diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm index 026806e..34ba039 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm @@ -35,10 +35,10 @@ has '+csv_required_columns' => ( sub import_csv { my ($self) = @_; - my $rows = $self->csv_data; + $self->check_headers; my $lcc_org = $self->target_entity; - foreach my $row (@{$rows}) { + while ( my $row = $self->get_csv_line ) { $self->_row_to_result($row, $lcc_org); } } From f33100ba87e000d7787e0de94a72635553b0f808 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 11 Sep 2019 15:02:08 +0100 Subject: [PATCH 237/289] flash fixes on import --- lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm | 12 +++++++++--- lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm | 2 +- templates/admin/import_from/index.html.ep | 10 ---------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm b/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm index aa7a6b4..78cc590 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm @@ -37,7 +37,9 @@ sub post_suppliers { my $job_id = $c->minion->enqueue('csv_supplier_import' => [ $filename ]); - $c->flash(success => "CSV import started, see status of minion job at: " . $c->link_to( 'Minion Job', "/admin/minion/jobs?id=$job_id")); + my $job_url = $c->url_for("/admin/minion/jobs?id=$job_id")->to_abs; + + $c->flash(success => "CSV import started, see status of minion job at: $job_url"); return $c->redirect_to('/admin/import_from'); } @@ -63,7 +65,9 @@ sub post_postcodes { my $job_id = $c->minion->enqueue('csv_postcode_import' => [ $filename ]); - $c->flash(success => "CSV import started, see status of minion job at: " . $c->link_to( 'Minion Job', "/admin/minion/jobs?id=$job_id")); + my $job_url = $c->url_for("/admin/minion/jobs?id=$job_id")->to_abs; + + $c->flash(success => "CSV import started, see status of minion job at: $job_url"); return $c->redirect_to('/admin/import_from'); } @@ -94,7 +98,9 @@ sub post_transactions { my $job_id = $c->minion->enqueue('csv_transaction_import' => [ $filename, $c->param('entity_id') ]); - $c->flash(success => "CSV import started, see status of minion job at: " . $c->link_to( 'Minion Job', "/admin/minion/jobs?id=$job_id")); + my $job_url = $c->url_for("/admin/minion/jobs?id=$job_id")->to_abs; + + $c->flash(success => "CSV import started, see status of minion job at: $job_url"); return $c->redirect_to('/admin/import_from'); } diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm index 34ba039..5af13fe 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm @@ -87,7 +87,7 @@ sub _row_to_result { pattern => '%m/%d/%Y', time_zone => 'Europe/London' ); - + my $paid_date = ( $row->{paid_date} ? $date_formatter->parse_datetime($row->{paid_date}) : $date_formatter->parse_datetime($row->{invoice_date}) ); diff --git a/templates/admin/import_from/index.html.ep b/templates/admin/import_from/index.html.ep index 068c0d5..0dd5734 100644 --- a/templates/admin/import_from/index.html.ep +++ b/templates/admin/import_from/index.html.ep @@ -16,16 +16,6 @@ $(function() { }) % end -% if (my $error = flash 'error') { - -% } -% elsif (my $success = flash 'success') { - -% }

Import From

From 211c6a4c3e76d6ec44264f1f6978858412025bfa Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Mon, 16 Sep 2019 10:43:44 +0100 Subject: [PATCH 238/289] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0863a9b..1f0ab05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ # Next Release +# v0.10.10 + * Added proper minion job support * **Admin Feature** Added importing of CSVs from Lancaster City Council * Added pagination support to searching of organisations during transaction submission in API From 558e7e1c428682f5ce1c7d67598c1ed9d5954fc2 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Mon, 16 Sep 2019 10:46:38 +0100 Subject: [PATCH 239/289] Update perl version in Travis CI --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0b9a6c2..5777386 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ language: perl # postgresql: "9.6" perl: - - "5.20" + - "5.26" env: - HARNESS_PERL_SWITCHES="-MDevel::Cover" install: From 97e9d63f8c7382e9bfd7f80f98d4177bf2b86b43 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Tue, 25 Aug 2020 17:38:10 +0100 Subject: [PATCH 240/289] Update and clarify README --- README.md | 122 +++++++++++++++++++++++------------------------------- 1 file changed, 52 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index ab883ed..5747f47 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# Pear LocalLoop Server +# LocalSpend - Server + +This repository contains the server for the LocalSpend system. ## Current Status @@ -6,35 +8,40 @@ *Development:* [![Build Status](https://travis-ci.org/Pear-Trading/Foodloop-Server.svg?branch=development)](https://travis-ci.org/Pear-Trading/Foodloop-Server) -# Testing +# Test Environment + +## Running Tests -To run the main test framework, first install all the dependencies, then run the tests: +To run the main test framework, first install all the dependencies, then run +the tests: ``` cpanm --installdeps . prove -lr ``` -To run the main framework against a PostgreSQL backend, assuming you have postgres installed, you will need some extra dependencies first: +To run the main framework against a PostgreSQL backend, assuming you have +`postgres` installed, you will need some extra dependencies first: ``` cpanm --installdeps . --with-feature postgres PEAR_TEST_PG=1 prove -lr ``` -# Minion +## Setting Up Minion -to set up minion support, you will need to create a database and user for -minion to connect to. In production his should be a PostgreSQL database, -however an SQLite db can be used in testing. +To set up Minion support, you will need to create a database and user for +it to connect to. +In production his should be a PostgreSQL database, however SQLite can be used +in testing. -To use the SQLite version, run the following commands: +To use the SQLite version, run the following command: ``` cpanm --installdeps --with-feature sqlite . ``` -And then add the following to your configuration file: +And then ensure that the following is in your configuration file: ``` minion => { @@ -42,28 +49,30 @@ And then add the following to your configuration file: }, ``` -This will then use an SQLite db for the minion backend, using `minion.db` as -the database file. To start the minion itself, run: +This will then use an SQLite DB for the Minion backend, using `minion.db` as +the database file. +To start the minion itself, run: ``` ./script/pear-local_loop minion worker ``` -# Importing Ward Data +## Importing Ward Data -To import ward data, get the ward data csv and then run the following command: +To import ward data, download CSV(s) from [here](https://www.doogal.co.uk/PostcodeDownloads.php) and then run the following command: ```shell script ./script/pear-local_loop minion job \ --enqueue 'csv_postcode_import' \ - --args '[ "/path/to/ward/csv" ]' + --args '[ "⟨ path to CSV ⟩ ]' ``` -# Setting up Entity Postcodes +## Setting Up Entity Postcodes -Assuming you have imported codepoint open, then to properly assign all - postcodes: - +1. Import Code-Point Open: + - included in `etc/` + - `./script/pear-local_loop codepoint_open --outcodes LA1` +1. Assign postcodes: ```shell script ./script/pear-local_loop minion job \ --enqueue entity_postcode_lookup @@ -81,56 +90,35 @@ psql=# alter user minion with encrypted password 'abc123'; psql=# grant all privileges on database localloop_minion to minion; ``` -# Development +# Development Environment There are a couple of setup steps to getting a development environment ready. -Use the corresponding instructions depending on what state your current setup -is in. ## First Time Setup -First, decide if you're using SQLite or PostgreSQL locally. Development supports -both, however production uses PostgreSQL. For this example we will use SQLite. -As the default config is set up for this, no configuration changes are -needed initially. So, first off, install dependencies: - -```shell script -cpanm --installdeps . --with-feature=sqlite -``` - -Then install the database: - -```shell script -./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db' -``` - -Then set up the development users: - -```shell script -./script/pear-local_loop dev_data --force -``` - -***Note: do NOT run that script on production.*** - -Then you can start the application: - -```shell script -morbo script/pear-local_loop -l http://*:3000 -``` - -You can modify the host and port for listening as needed. - -# Old Docs - -## Local test database - -To install a local DB: - -``` -./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db' -``` - -To do an upgrade of it after making DB changes to commit: +1. Decide if you're using SQLite or PostgreSQL locally. + - Development supports both, however production uses PostgreSQL. + - For this example we will use SQLite. + - As the default config. is set up for this, no configuration changes are +needed initially. +1. Install dependencies: + - `cpanm --installdeps . --with-feature=sqlite --with-feature=codepoint-open` +1. Install the database: + - `./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db'` +1. Set up the development users: + - `./script/pear-local_loop dev_data --force` + - ***DO NOT RUN ON PROD.*** +1. Start the minion: + - `./script/pear-local_loop minion worker` +1. Import ward data (see Production instructions above) +1. Set up postcodes (see Production intructions above) +1. Start the application: + - `morbo script/pear-local_loop -l http://*:3000` + - You can modify the host and port as needed. + +## Database Scripts + +To upgrade the database after making changes to commit: ``` ./script/deploy_db write_ddl -c 'dbi:SQLite:dbname=foodloop.db' @@ -142,9 +130,3 @@ To redo leaderboards: ``` ./script/pear-local_loop recalc_leaderboards ``` - -To serve a test version locally of the server: - -``` -morbo script/pear-local_loop -``` From b8b841ccbf78d80a321de077a7801a1758b122f7 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Tue, 25 Aug 2020 17:44:06 +0100 Subject: [PATCH 241/289] Minor README amendments --- README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5747f47..7369656 100644 --- a/README.md +++ b/README.md @@ -59,13 +59,11 @@ To start the minion itself, run: ## Importing Ward Data -To import ward data, download CSV(s) from [here](https://www.doogal.co.uk/PostcodeDownloads.php) and then run the following command: +To import ward data: -```shell script -./script/pear-local_loop minion job \ - --enqueue 'csv_postcode_import' \ - --args '[ "⟨ path to CSV ⟩ ]' -``` +1. Download CSV(s) from [here](https://www.doogal.co.uk/PostcodeDownloads.php) +1. Run the following command: + -- `./script/pear-local_loop minion job --enqueue 'csv_postcode_import' --args '[ "⟨ path to CSV ⟩ ]'` ## Setting Up Entity Postcodes @@ -110,8 +108,8 @@ needed initially. - ***DO NOT RUN ON PROD.*** 1. Start the minion: - `./script/pear-local_loop minion worker` -1. Import ward data (see Production instructions above) -1. Set up postcodes (see Production intructions above) +1. Import ward data (see [instructions](#importing-ward-data) above) +1. Set up postcodes (see [intructions](#setting-up-entity-postcodes) above) 1. Start the application: - `morbo script/pear-local_loop -l http://*:3000` - You can modify the host and port as needed. From c46677bbca8795d5017fb31ec120f7ca82f52f58 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Tue, 25 Aug 2020 17:50:11 +0100 Subject: [PATCH 242/289] Minor README amendments --- README.md | 53 ++++++++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 7369656..4f641f7 100644 --- a/README.md +++ b/README.md @@ -15,18 +15,14 @@ This repository contains the server for the LocalSpend system. To run the main test framework, first install all the dependencies, then run the tests: -``` -cpanm --installdeps . -prove -lr -``` +- `cpanm --installdeps .` +- `prove -lr` To run the main framework against a PostgreSQL backend, assuming you have `postgres` installed, you will need some extra dependencies first: -``` -cpanm --installdeps . --with-feature postgres -PEAR_TEST_PG=1 prove -lr -``` +- `cpanm --installdeps . --with-feature postgres` +- `PEAR_TEST_PG=1 prove -lr` ## Setting Up Minion @@ -35,27 +31,22 @@ it to connect to. In production his should be a PostgreSQL database, however SQLite can be used in testing. -To use the SQLite version, run the following command: - -``` -cpanm --installdeps --with-feature sqlite . -``` +To use the SQLite version: -And then ensure that the following is in your configuration file: - -``` - minion => { - SQLite => 'sqlite:minion.db', - }, -``` +1. Install the SQLite dependencies: + - `cpanm --installdeps --with-feature sqlite .` +2. Ensure that the following is in your configuration file: + - ``` + minion => { + SQLite => 'sqlite:minion.db', + }, + ``` This will then use an SQLite DB for the Minion backend, using `minion.db` as the database file. -To start the minion itself, run: -``` -./script/pear-local_loop minion worker -``` +To start the minion itself, run this command: +- `./script/pear-local_loop minion worker` ## Importing Ward Data @@ -63,7 +54,11 @@ To import ward data: 1. Download CSV(s) from [here](https://www.doogal.co.uk/PostcodeDownloads.php) 1. Run the following command: - -- `./script/pear-local_loop minion job --enqueue 'csv_postcode_import' --args '[ "⟨ path to CSV ⟩ ]'` + - ```shell script + ./script/pear-local_loop minion job \ + --enqueue 'csv_postcode_import' \ + --args '[ "⟨ path to CSV ⟩ ]' + ``` ## Setting Up Entity Postcodes @@ -71,10 +66,10 @@ To import ward data: - included in `etc/` - `./script/pear-local_loop codepoint_open --outcodes LA1` 1. Assign postcodes: -```shell script -./script/pear-local_loop minion job \ - --enqueue entity_postcode_lookup -``` + - ```shell script + ./script/pear-local_loop minion job \ + --enqueue entity_postcode_lookup + ``` ## Example PostgreSQL setup From d17ba867af942ab4650a6e9a2ac8343c6dca42cf Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Tue, 25 Aug 2020 17:52:08 +0100 Subject: [PATCH 243/289] Minor README amendments --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4f641f7..fdc3428 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,11 @@ There are a couple of setup steps to getting a development environment ready. - As the default config. is set up for this, no configuration changes are needed initially. 1. Install dependencies: - - `cpanm --installdeps . --with-feature=sqlite --with-feature=codepoint-open` + - ```shell script + cpanm --installdeps . \ + --with-feature=sqlite \ + --with-feature=codepoint-open + ``` 1. Install the database: - `./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db'` 1. Set up the development users: @@ -113,13 +117,9 @@ needed initially. To upgrade the database after making changes to commit: -``` -./script/deploy_db write_ddl -c 'dbi:SQLite:dbname=foodloop.db' -./script/deploy_db upgrade -c 'dbi:SQLite:dbname=foodloop.db' -``` +1. `./script/deploy_db write_ddl -c 'dbi:SQLite:dbname=foodloop.db'` +1. `./script/deploy_db upgrade -c 'dbi:SQLite:dbname=foodloop.db'` To redo leaderboards: -``` -./script/pear-local_loop recalc_leaderboards -``` +1. `./script/pear-local_loop recalc_leaderboards` From 50a8139cfae3842d063d53f9bc091014046aea8d Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Tue, 25 Aug 2020 17:53:12 +0100 Subject: [PATCH 244/289] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fdc3428..e281e2e 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ needed initially. 1. Start the minion: - `./script/pear-local_loop minion worker` 1. Import ward data (see [instructions](#importing-ward-data) above) -1. Set up postcodes (see [intructions](#setting-up-entity-postcodes) above) +1. Set up postcodes (see [instructions](#setting-up-entity-postcodes) above) 1. Start the application: - `morbo script/pear-local_loop -l http://*:3000` - You can modify the host and port as needed. From 71de03b449239d22a2f689907cf2da92895938e3 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Wed, 26 Aug 2020 14:11:39 +0100 Subject: [PATCH 245/289] Add environment file step --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e281e2e..3ae5b1a 100644 --- a/README.md +++ b/README.md @@ -104,11 +104,12 @@ needed initially. - `./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db'` 1. Set up the development users: - `./script/pear-local_loop dev_data --force` - - ***DO NOT RUN ON PROD.*** + - **DO NOT RUN ON PROD.** 1. Start the minion: - `./script/pear-local_loop minion worker` 1. Import ward data (see [instructions](#importing-ward-data) above) 1. Set up postcodes (see [instructions](#setting-up-entity-postcodes) above) +1. Create an `environment.dev.ts` file in `src/environments` with your API keys 1. Start the application: - `morbo script/pear-local_loop -l http://*:3000` - You can modify the host and port as needed. From 6d71d51581165f56a8c19286c89737d3e46d35f6 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Wed, 14 Oct 2020 13:40:41 +0100 Subject: [PATCH 246/289] Commit database files --- share/ddl/PostgreSQL/deploy/30/001-auto-__VERSION.sql | 6 +++--- share/ddl/PostgreSQL/deploy/30/001-auto.sql | 6 +++--- share/ddl/SQLite/deploy/30/001-auto-__VERSION.sql | 6 +++--- share/ddl/SQLite/deploy/30/001-auto.sql | 6 +++--- share/ddl/_source/deploy/30/001-auto-__VERSION.yml | 2 +- share/ddl/_source/deploy/30/001-auto.yml | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/share/ddl/PostgreSQL/deploy/30/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/30/001-auto-__VERSION.sql index b8b6d70..f8a54df 100644 --- a/share/ddl/PostgreSQL/deploy/30/001-auto-__VERSION.sql +++ b/share/ddl/PostgreSQL/deploy/30/001-auto-__VERSION.sql @@ -1,7 +1,7 @@ --- +-- -- Created by SQL::Translator::Producer::PostgreSQL --- Created on Mon Sep 2 13:06:08 2019 --- +-- Created on Tue Aug 25 15:48:43 2020 +-- ; -- -- Table: dbix_class_deploymenthandler_versions diff --git a/share/ddl/PostgreSQL/deploy/30/001-auto.sql b/share/ddl/PostgreSQL/deploy/30/001-auto.sql index 357c4a8..0927410 100644 --- a/share/ddl/PostgreSQL/deploy/30/001-auto.sql +++ b/share/ddl/PostgreSQL/deploy/30/001-auto.sql @@ -1,7 +1,7 @@ --- +-- -- Created by SQL::Translator::Producer::PostgreSQL --- Created on Mon Sep 2 13:06:08 2019 --- +-- Created on Tue Aug 25 15:48:42 2020 +-- ; -- -- Table: account_tokens diff --git a/share/ddl/SQLite/deploy/30/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/30/001-auto-__VERSION.sql index 21f87c4..d08c60c 100644 --- a/share/ddl/SQLite/deploy/30/001-auto-__VERSION.sql +++ b/share/ddl/SQLite/deploy/30/001-auto-__VERSION.sql @@ -1,7 +1,7 @@ --- +-- -- Created by SQL::Translator::Producer::SQLite --- Created on Mon Sep 2 13:06:08 2019 --- +-- Created on Tue Aug 25 15:48:43 2020 +-- ; BEGIN TRANSACTION; diff --git a/share/ddl/SQLite/deploy/30/001-auto.sql b/share/ddl/SQLite/deploy/30/001-auto.sql index 320ab24..2962bd1 100644 --- a/share/ddl/SQLite/deploy/30/001-auto.sql +++ b/share/ddl/SQLite/deploy/30/001-auto.sql @@ -1,7 +1,7 @@ --- +-- -- Created by SQL::Translator::Producer::SQLite --- Created on Mon Sep 2 13:06:08 2019 --- +-- Created on Tue Aug 25 15:48:43 2020 +-- ; BEGIN TRANSACTION; diff --git a/share/ddl/_source/deploy/30/001-auto-__VERSION.yml b/share/ddl/_source/deploy/30/001-auto-__VERSION.yml index 2cc0cbf..7f96b5c 100644 --- a/share/ddl/_source/deploy/30/001-auto-__VERSION.yml +++ b/share/ddl/_source/deploy/30/001-auto-__VERSION.yml @@ -88,4 +88,4 @@ translator: producer_type: SQL::Translator::Producer::YAML show_warnings: 0 trace: 0 - version: 0.11024 + version: 1.61 diff --git a/share/ddl/_source/deploy/30/001-auto.yml b/share/ddl/_source/deploy/30/001-auto.yml index 7e4a6d2..0c2e4c7 100644 --- a/share/ddl/_source/deploy/30/001-auto.yml +++ b/share/ddl/_source/deploy/30/001-auto.yml @@ -3547,4 +3547,4 @@ translator: producer_type: SQL::Translator::Producer::YAML show_warnings: 0 trace: 0 - version: 0.11024 + version: 1.61 From 4a71b7cf129686bbf2c77ca0ea716da8d78e33c8 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Wed, 14 Oct 2020 13:40:56 +0100 Subject: [PATCH 247/289] Add troubleshooting information --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 3ae5b1a..abc24f6 100644 --- a/README.md +++ b/README.md @@ -124,3 +124,19 @@ To upgrade the database after making changes to commit: To redo leaderboards: 1. `./script/pear-local_loop recalc_leaderboards` + +# Troubleshooting + +## ‘Can't write to /usr/local/share/perl/5.30.0 and /usr/local/bin: Installing modules to /home//perl5’ when running `cpanm` commands + +Intall `local::lib` by running the following commands: + +``` + cpanm --local-lib=~/perl5 local::lib && eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib) +``` + +NB: You must run this in each Terminal window; I don't know why. + +## ‘Can't load application from file "/script/pear-local_loop": Can't locate Data/UUID.pm in @INC (you may need to install the DATA::UUID module)’ when running server + +Ensure you have run the `cpan --installdeps` command. From fc9cfe6cd461322143af5cfac0c78c8d45cb79c5 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Sun, 18 Oct 2020 14:25:21 +0100 Subject: [PATCH 248/289] Fix is_empty tests --- lib/Pear/LocalLoop/Controller/Api/Feedback.pm | 2 +- lib/Pear/LocalLoop/Controller/Api/Register.pm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm index cda98f1..d5e4bfa 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm @@ -34,7 +34,7 @@ sub post_feedback { my $user_rs = $c->schema->resultset('User'); $validation->required('email')->in_resultset( 'email', $user_rs ); - $validation->required('feedbacktext'); + $validation->required('feedbacktext', 'not_empty'); $validation->required('app_name'); $validation->required('package_name'); $validation->required('version_code'); diff --git a/lib/Pear/LocalLoop/Controller/Api/Register.pm b/lib/Pear/LocalLoop/Controller/Api/Register.pm index fc8ed0b..aee6b80 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Register.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Register.pm @@ -69,8 +69,8 @@ sub post_register { my $usertype = $validation->param('usertype') || ''; if ( $usertype eq 'customer' ) { - $validation->required('display_name'); - $validation->required('full_name'); + $validation->required('display_name', 'not_empty'); + $validation->required('full_name', 'not_empty'); my $year = DateTime->now->year; $validation->required('year_of_birth')->number->gt_num($year - 150)->lt_num($year - 10); } elsif ( $usertype eq 'organisation' ) { From a3923b7f6f2b26968eb6abadffef6bc9d53d5172 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Sun, 18 Oct 2020 14:38:47 +0100 Subject: [PATCH 249/289] Revert "Commit database files" This reverts commit c5878b3a08e3b77013f5ac6ff3d5c2746767d6ef. --- share/ddl/PostgreSQL/deploy/30/001-auto-__VERSION.sql | 6 +++--- share/ddl/PostgreSQL/deploy/30/001-auto.sql | 6 +++--- share/ddl/SQLite/deploy/30/001-auto-__VERSION.sql | 6 +++--- share/ddl/SQLite/deploy/30/001-auto.sql | 6 +++--- share/ddl/_source/deploy/30/001-auto-__VERSION.yml | 2 +- share/ddl/_source/deploy/30/001-auto.yml | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/share/ddl/PostgreSQL/deploy/30/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/30/001-auto-__VERSION.sql index f8a54df..b8b6d70 100644 --- a/share/ddl/PostgreSQL/deploy/30/001-auto-__VERSION.sql +++ b/share/ddl/PostgreSQL/deploy/30/001-auto-__VERSION.sql @@ -1,7 +1,7 @@ --- +-- -- Created by SQL::Translator::Producer::PostgreSQL --- Created on Tue Aug 25 15:48:43 2020 --- +-- Created on Mon Sep 2 13:06:08 2019 +-- ; -- -- Table: dbix_class_deploymenthandler_versions diff --git a/share/ddl/PostgreSQL/deploy/30/001-auto.sql b/share/ddl/PostgreSQL/deploy/30/001-auto.sql index 0927410..357c4a8 100644 --- a/share/ddl/PostgreSQL/deploy/30/001-auto.sql +++ b/share/ddl/PostgreSQL/deploy/30/001-auto.sql @@ -1,7 +1,7 @@ --- +-- -- Created by SQL::Translator::Producer::PostgreSQL --- Created on Tue Aug 25 15:48:42 2020 --- +-- Created on Mon Sep 2 13:06:08 2019 +-- ; -- -- Table: account_tokens diff --git a/share/ddl/SQLite/deploy/30/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/30/001-auto-__VERSION.sql index d08c60c..21f87c4 100644 --- a/share/ddl/SQLite/deploy/30/001-auto-__VERSION.sql +++ b/share/ddl/SQLite/deploy/30/001-auto-__VERSION.sql @@ -1,7 +1,7 @@ --- +-- -- Created by SQL::Translator::Producer::SQLite --- Created on Tue Aug 25 15:48:43 2020 --- +-- Created on Mon Sep 2 13:06:08 2019 +-- ; BEGIN TRANSACTION; diff --git a/share/ddl/SQLite/deploy/30/001-auto.sql b/share/ddl/SQLite/deploy/30/001-auto.sql index 2962bd1..320ab24 100644 --- a/share/ddl/SQLite/deploy/30/001-auto.sql +++ b/share/ddl/SQLite/deploy/30/001-auto.sql @@ -1,7 +1,7 @@ --- +-- -- Created by SQL::Translator::Producer::SQLite --- Created on Tue Aug 25 15:48:43 2020 --- +-- Created on Mon Sep 2 13:06:08 2019 +-- ; BEGIN TRANSACTION; diff --git a/share/ddl/_source/deploy/30/001-auto-__VERSION.yml b/share/ddl/_source/deploy/30/001-auto-__VERSION.yml index 7f96b5c..2cc0cbf 100644 --- a/share/ddl/_source/deploy/30/001-auto-__VERSION.yml +++ b/share/ddl/_source/deploy/30/001-auto-__VERSION.yml @@ -88,4 +88,4 @@ translator: producer_type: SQL::Translator::Producer::YAML show_warnings: 0 trace: 0 - version: 1.61 + version: 0.11024 diff --git a/share/ddl/_source/deploy/30/001-auto.yml b/share/ddl/_source/deploy/30/001-auto.yml index 0c2e4c7..7e4a6d2 100644 --- a/share/ddl/_source/deploy/30/001-auto.yml +++ b/share/ddl/_source/deploy/30/001-auto.yml @@ -3547,4 +3547,4 @@ translator: producer_type: SQL::Translator::Producer::YAML show_warnings: 0 trace: 0 - version: 1.61 + version: 0.11024 From 0eabd9cf1e1d1ddda42e9010dfbbe99c9908c4af Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Sun, 1 Nov 2020 18:06:11 +0000 Subject: [PATCH 250/289] Add API endpoint for sending push notis --- lib/Pear/LocalLoop.pm | 2 + .../LocalLoop/Controller/Api/Sendmessage.pm | 42 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index caa62ae..29121dc 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -141,6 +141,8 @@ sub startup { $api_public->post('/register')->to('api-register#post_register'); $api_public->post('/logout')->to('api-auth#post_logout'); $api_public->post('/feedback')->to('api-feedback#post_feedback'); + $api_public->post('/send-message')->to('api-sendmessage#post_message'); + #$api_public->post('/send-message')->to('api-sendmessage#post_message'); # Private, must be authenticated api routes my $api = $api_public->under('/')->to('api-auth#auth'); diff --git a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm new file mode 100644 index 0000000..1dd8a4c --- /dev/null +++ b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm @@ -0,0 +1,42 @@ +package Pear::LocalLoop::Controller::Api::Sendmessage; +use Mojo::Base 'Mojolicious::Controller'; + +has error_messages => sub { + return { + email => { + required => { message => 'Email is required or not registered', status => 400 }, + in_resultset => { message => 'Email is required or not registered', status => 400, error => "required" }, + }, + messagetext => { + required => { message => 'Message is required', status => 400 }, + }, + }; +}; + +sub post_message { + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + my $user_rs = $c->schema->resultset('User'); + + # $validation->required('email')->in_resultset( 'email', $user_rs ); + $validation->required('messagetext'); + + return $c->api_validation_error if $validation->has_error; + + my $user = $user_rs->find({'email' => $validation->param('email')}); +=begin comment + $c->schema->resultset('Feedback')->create({ + user => $user, + messagetext => $validation->param('messagetext'), + }); +=cut + return $c->render( json => { + success => Mojo::JSON->true, + message => 'Your message has been sent successfully!', + }); +} + +1; From f57dc632778f5b44773a412b9e8bbf564baba394 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Sun, 8 Nov 2020 15:00:44 +0000 Subject: [PATCH 251/289] Add postcode CSVs to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 3dd59f9..3d4ea4b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ schema.png etc/code-point-open/codepo_gb/ pear-local_loop.production.conf + +localspend-47012.json +*postcodes.csv From 279127a6d4cd0f1ac4cee17215683508214c2087 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Sun, 8 Nov 2020 15:05:53 +0000 Subject: [PATCH 252/289] Add API message function --- lib/Pear/LocalLoop.pm | 2 +- .../LocalLoop/Controller/Api/Sendmessage.pm | 73 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 29121dc..c665cd6 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -141,8 +141,8 @@ sub startup { $api_public->post('/register')->to('api-register#post_register'); $api_public->post('/logout')->to('api-auth#post_logout'); $api_public->post('/feedback')->to('api-feedback#post_feedback'); + $api_public->post('/add-device-token')->to('api-devices#add_token'); $api_public->post('/send-message')->to('api-sendmessage#post_message'); - #$api_public->post('/send-message')->to('api-sendmessage#post_message'); # Private, must be authenticated api routes my $api = $api_public->under('/')->to('api-auth#auth'); diff --git a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm index 1dd8a4c..4ec0b82 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm @@ -1,5 +1,10 @@ package Pear::LocalLoop::Controller::Api::Sendmessage; use Mojo::Base 'Mojolicious::Controller'; +use LWP::UserAgent; +use JSON; +use Mojo::JWT; +use Mojo::File; +use Carp; has error_messages => sub { return { @@ -13,6 +18,46 @@ has error_messages => sub { }; }; +=begin comment + Credit: Peter Scott/StackOverflow + https://stackoverflow.com/a/53357961/4580273 + Credit: jeffez/StackOverflow + https://stackoverflow.com/q/56556438/4580273 +=cut + +my $jwt = create_jwt_from_path_and_scopes('./localspend-47012.json', 'email https://www.googleapis.com/auth/compute'); +my $ua = LWP::UserAgent->new(); + +my $bearer_token = $ua->post('https://www.googleapis.com/oauth2/v4/token', + { + 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', + 'assertion' => $jwt + } +); + +sub create_jwt_from_path_and_scopes +{ + my ( $path, $scope ) = @_; + croak("No path provided") if not defined $path; + croak("$path not available") if not -f $path; + my $json = decode_json( Mojo::File->new($path)->slurp ); + croak("No Private key in $path") if not defined $json->{private_key}; + croak("Not a service account") if $json->{type} ne 'service_account'; + my $jwt = Mojo::JWT->new(); + $jwt->algorithm('RS256'); + $jwt->secret($json->{private_key}); + + $jwt->claims( { + iss => $json->{client_email}, + scope => $scope, + aud => 'https://www.googleapis.com/oauth2/v4/token', + iat => time(), + exp => time()+3600 + } ); + $jwt->set_iat( 1 ); + return $jwt->encode; +} + sub post_message { my $c = shift; @@ -27,6 +72,34 @@ sub post_message { return $c->api_validation_error if $validation->has_error; my $user = $user_rs->find({'email' => $validation->param('email')}); + + my $end_point = "https://fcm.googleapis.com/v1/projects/localspend-47012/messages:send"; + + my $request = HTTP::Request->new('POST', $end_point); + $request->header('Authorization' => "Bearer $bearer_token"); + $request->header('Content-Type' => 'application/json'); + + $request->content(JSON::encode_json ({ + message => { + token => $user->param('token'), + notification => { + title => 'test', + body => 'test content' + }, + webpush => { + headers => { + Urgency => 'high' + }, + notification => { + body => 'test content', + requireInteraction => 'true' + } + } + } + })); + + $ua->request($request); + =begin comment $c->schema->resultset('Feedback')->create({ user => $user, From 7500f95d88d7b6118e53ffe97f5945badfa53a90 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Sun, 8 Nov 2020 15:15:28 +0000 Subject: [PATCH 253/289] Add device token registration --- .../LocalLoop/Schema/Result/DeviceToken.pm | 47 +++++++++++++++++++ lib/Pear/LocalLoop/Schema/Result/User.pm | 7 +++ 2 files changed, 54 insertions(+) create mode 100644 lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm diff --git a/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm b/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm new file mode 100644 index 0000000..3fd4686 --- /dev/null +++ b/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm @@ -0,0 +1,47 @@ +package Pear::LocalLoop::Schema::Result::DeviceToken; + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +__PACKAGE__->load_components( qw/ + InflateColumn::DateTime + TimeStamp + FilterColumn +/); + +__PACKAGE__->table("device_tokens"); + +__PACKAGE__->add_columns( + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "user_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "token" => { + data_type => "varchar", + size => 200, + is_nullable => 0, + }, + "register_date" => { + data_type => "datetime", + set_on_create => 1, + }, +); + +__PACKAGE__->set_primary_key("id"); + +__PACKAGE__->belongs_to( + "user", + "Pear::LocalLoop::Schema::Result::User", + { id => "user_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, +); + +1; diff --git a/lib/Pear/LocalLoop/Schema/Result/User.pm b/lib/Pear/LocalLoop/Schema/Result/User.pm index 9eee628..300d820 100644 --- a/lib/Pear/LocalLoop/Schema/Result/User.pm +++ b/lib/Pear/LocalLoop/Schema/Result/User.pm @@ -71,6 +71,13 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); +__PACKAGE__->has_many( + "device_tokens", + "Pear::LocalLoop::Schema::Result::DeviceToken", + { "foreign.user_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + __PACKAGE__->has_many( "feedback", "Pear::LocalLoop::Schema::Result::Feedback", From 5b0bea78b7bc64562958d09f3b2848db8b68a590 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Sun, 8 Nov 2020 17:35:29 +0000 Subject: [PATCH 254/289] Add push noti sending --- lib/Pear/LocalLoop/Controller/Api/Auth.pm | 1 + .../LocalLoop/Controller/Api/Sendmessage.pm | 68 +++++++++++-------- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Auth.pm b/lib/Pear/LocalLoop/Controller/Api/Auth.pm index cf6b466..6995e2f 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Auth.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Auth.pm @@ -85,6 +85,7 @@ sub post_login { return $c->render( json => { success => Mojo::JSON->true, session_key => $session_key, + email => $email, display_name => $user_result->name, user_type => $user_result->type, }); diff --git a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm index 4ec0b82..bb6becd 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm @@ -2,15 +2,18 @@ package Pear::LocalLoop::Controller::Api::Sendmessage; use Mojo::Base 'Mojolicious::Controller'; use LWP::UserAgent; use JSON; +use JSON::Parse 'parse_json'; use Mojo::JWT; use Mojo::File; use Carp; has error_messages => sub { return { - email => { - required => { message => 'Email is required or not registered', status => 400 }, - in_resultset => { message => 'Email is required or not registered', status => 400, error => "required" }, + devicetoken => { + required => { message => 'Device token is required or not registered', status => 400 }, + }, + sender => { + required => { message => 'Sender name is required', status => 400 }, }, messagetext => { required => { message => 'Message is required', status => 400 }, @@ -25,16 +28,19 @@ has error_messages => sub { https://stackoverflow.com/q/56556438/4580273 =cut -my $jwt = create_jwt_from_path_and_scopes('./localspend-47012.json', 'email https://www.googleapis.com/auth/compute'); +my $jwt = create_jwt_from_path_and_scopes('./localspend-47012.json', 'email https://www.googleapis.com/auth/cloud-platform'); + my $ua = LWP::UserAgent->new(); -my $bearer_token = $ua->post('https://www.googleapis.com/oauth2/v4/token', +my $response = $ua->post('https://www.googleapis.com/oauth2/v4/token', { 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $jwt } ); +my $bearer_token = parse_json($response->content); + sub create_jwt_from_path_and_scopes { my ( $path, $scope ) = @_; @@ -66,50 +72,58 @@ sub post_message { my $user_rs = $c->schema->resultset('User'); - # $validation->required('email')->in_resultset( 'email', $user_rs ); + $validation->required('devicetoken'); + $validation->required('sender'); $validation->required('messagetext'); return $c->api_validation_error if $validation->has_error; - my $user = $user_rs->find({'email' => $validation->param('email')}); - my $end_point = "https://fcm.googleapis.com/v1/projects/localspend-47012/messages:send"; my $request = HTTP::Request->new('POST', $end_point); - $request->header('Authorization' => "Bearer $bearer_token"); + $request->header('Authorization' => "Bearer $bearer_token->{access_token}"); $request->header('Content-Type' => 'application/json'); $request->content(JSON::encode_json ({ message => { - token => $user->param('token'), + token => $validation->param('devicetoken'), notification => { - title => 'test', - body => 'test content' + title => $validation->param('sender'), + body => $validation->param('messagetext') }, webpush => { headers => { - Urgency => 'high' + urgency => 'very-low' }, notification => { - body => 'test content', - requireInteraction => 'true' + title => $validation->param('sender'), + body => $validation->param('messagetext'), } } } })); - $ua->request($request); - -=begin comment - $c->schema->resultset('Feedback')->create({ - user => $user, - messagetext => $validation->param('messagetext'), - }); -=cut - return $c->render( json => { - success => Mojo::JSON->true, - message => 'Your message has been sent successfully!', - }); + my $response = $ua->request($request); + + if ($response->is_success) { + return $c->render( json => { + success => Mojo::JSON->true, + message => 'Your message has been sent successfully!', + }); + } elsif ($response->is_error) { + return $c->render( + json => { + success => Mojo::JSON->false, + message => [ + $response->decoded_content, + $jwt, + $bearer_token + ], + error => 'message_error', + }, + status => $response->code, + ); + } } 1; From ab53dbd409f2e69ef0d4336a324cabcf26deb8b7 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Wed, 18 Nov 2020 22:59:25 +0000 Subject: [PATCH 255/289] Add WWW::FCM::HTTP package --- cpanfile | 1 + 1 file changed, 1 insertion(+) diff --git a/cpanfile b/cpanfile index 4ea8baf..76dbb29 100644 --- a/cpanfile +++ b/cpanfile @@ -24,6 +24,7 @@ requires 'Text::CSV'; requires 'Try::Tiny'; requires 'Throwable::Error'; requires 'Minion'; +requires 'WWW::FCM::HTTP'; on 'test' => sub { requires 'Test::More'; From 1cbacc9bb093cdedb6fd771d28fc9f8b42032540 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Wed, 18 Nov 2020 22:59:50 +0000 Subject: [PATCH 256/289] Upgrade DB to add DeviceToken model --- lib/Pear/LocalLoop/Schema.pm | 2 +- .../deploy/31/001-auto-__VERSION.sql | 18 + share/ddl/PostgreSQL/deploy/31/001-auto.sql | 717 ++++ .../ddl/PostgreSQL/upgrade/30-31/001-auto.sql | 23 + .../SQLite/deploy/31/001-auto-__VERSION.sql | 18 + share/ddl/SQLite/deploy/31/001-auto.sql | 481 +++ share/ddl/SQLite/upgrade/30-31/001-auto.sql | 21 + .../_source/deploy/31/001-auto-__VERSION.yml | 91 + share/ddl/_source/deploy/31/001-auto.yml | 3629 +++++++++++++++++ 9 files changed, 4999 insertions(+), 1 deletion(-) create mode 100644 share/ddl/PostgreSQL/deploy/31/001-auto-__VERSION.sql create mode 100644 share/ddl/PostgreSQL/deploy/31/001-auto.sql create mode 100644 share/ddl/PostgreSQL/upgrade/30-31/001-auto.sql create mode 100644 share/ddl/SQLite/deploy/31/001-auto-__VERSION.sql create mode 100644 share/ddl/SQLite/deploy/31/001-auto.sql create mode 100644 share/ddl/SQLite/upgrade/30-31/001-auto.sql create mode 100644 share/ddl/_source/deploy/31/001-auto-__VERSION.yml create mode 100644 share/ddl/_source/deploy/31/001-auto.yml diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index 32652d0..f3add3a 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -6,7 +6,7 @@ use warnings; use base 'DBIx::Class::Schema'; -our $VERSION = 30; +our $VERSION = 31; __PACKAGE__->load_namespaces; diff --git a/share/ddl/PostgreSQL/deploy/31/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/31/001-auto-__VERSION.sql new file mode 100644 index 0000000..28f675c --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/31/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Wed Nov 18 22:58:25 2020 +-- +; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE "dbix_class_deploymenthandler_versions" ( + "id" serial NOT NULL, + "version" character varying(50) NOT NULL, + "ddl" text, + "upgrade_sql" text, + PRIMARY KEY ("id"), + CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version") +); + +; diff --git a/share/ddl/PostgreSQL/deploy/31/001-auto.sql b/share/ddl/PostgreSQL/deploy/31/001-auto.sql new file mode 100644 index 0000000..5883842 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/31/001-auto.sql @@ -0,0 +1,717 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Wed Nov 18 22:58:25 2020 +-- +; +-- +-- Table: account_tokens +-- +CREATE TABLE "account_tokens" ( + "id" serial NOT NULL, + "name" text NOT NULL, + "used" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "account_tokens_name" UNIQUE ("name") +); + +; +-- +-- Table: category +-- +CREATE TABLE "category" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "line_icon" character varying(255), + PRIMARY KEY ("id"), + CONSTRAINT "category_name" UNIQUE ("name") +); + +; +-- +-- Table: entities +-- +CREATE TABLE "entities" ( + "id" serial NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: external_references +-- +CREATE TABLE "external_references" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "external_references_name" UNIQUE ("name") +); + +; +-- +-- Table: gb_wards +-- +CREATE TABLE "gb_wards" ( + "id" serial NOT NULL, + "ward" character varying(100) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: global_medal_group +-- +CREATE TABLE "global_medal_group" ( + "id" serial NOT NULL, + "group_name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "global_medal_group_group_name" UNIQUE ("group_name") +); + +; +-- +-- Table: import_sets +-- +CREATE TABLE "import_sets" ( + "id" serial NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: leaderboards +-- +CREATE TABLE "leaderboards" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboards_type" UNIQUE ("type") +); + +; +-- +-- Table: org_medal_group +-- +CREATE TABLE "org_medal_group" ( + "id" serial NOT NULL, + "group_name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "org_medal_group_group_name" UNIQUE ("group_name") +); + +; +-- +-- Table: organisation_social_types +-- +CREATE TABLE "organisation_social_types" ( + "id" serial NOT NULL, + "key" character varying(255) NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisation_social_types_key" UNIQUE ("key") +); + +; +-- +-- Table: organisation_types +-- +CREATE TABLE "organisation_types" ( + "id" serial NOT NULL, + "key" character varying(255) NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisation_types_key" UNIQUE ("key") +); + +; +-- +-- Table: customers +-- +CREATE TABLE "customers" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "display_name" character varying(255) NOT NULL, + "full_name" character varying(255) NOT NULL, + "year_of_birth" integer NOT NULL, + "postcode" character varying(16) NOT NULL, + "latitude" numeric(5,2), + "longitude" numeric(5,2), + PRIMARY KEY ("id") +); +CREATE INDEX "customers_idx_entity_id" on "customers" ("entity_id"); + +; +-- +-- Table: entity_association +-- +CREATE TABLE "entity_association" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "lis" boolean, + "esta" boolean, + PRIMARY KEY ("id") +); +CREATE INDEX "entity_association_idx_entity_id" on "entity_association" ("entity_id"); + +; +-- +-- Table: gb_postcodes +-- +CREATE TABLE "gb_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) DEFAULT '' NOT NULL, + "latitude" numeric(7,5), + "longitude" numeric(7,5), + "ward_id" integer, + PRIMARY KEY ("outcode", "incode") +); +CREATE INDEX "gb_postcodes_idx_ward_id" on "gb_postcodes" ("ward_id"); + +; +-- +-- Table: global_medals +-- +CREATE TABLE "global_medals" ( + "id" serial NOT NULL, + "group_id" integer NOT NULL, + "threshold" integer NOT NULL, + "points" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_medals_idx_group_id" on "global_medals" ("group_id"); + +; +-- +-- Table: leaderboard_sets +-- +CREATE TABLE "leaderboard_sets" ( + "id" serial NOT NULL, + "leaderboard_id" integer NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "leaderboard_sets_idx_leaderboard_id" on "leaderboard_sets" ("leaderboard_id"); + +; +-- +-- Table: org_medals +-- +CREATE TABLE "org_medals" ( + "id" serial NOT NULL, + "group_id" integer NOT NULL, + "threshold" integer NOT NULL, + "points" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_medals_idx_group_id" on "org_medals" ("group_id"); + +; +-- +-- Table: transactions +-- +CREATE TABLE "transactions" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "proof_image" text, + "submitted_at" timestamp NOT NULL, + "purchase_time" timestamp NOT NULL, + "essential" boolean DEFAULT false NOT NULL, + "distance" numeric(15), + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_idx_buyer_id" on "transactions" ("buyer_id"); +CREATE INDEX "transactions_idx_seller_id" on "transactions" ("seller_id"); + +; +-- +-- Table: users +-- +CREATE TABLE "users" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "email" text NOT NULL, + "join_date" timestamp NOT NULL, + "password" character varying(100) NOT NULL, + "is_admin" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "users_email" UNIQUE ("email") +); +CREATE INDEX "users_idx_entity_id" on "users" ("entity_id"); + +; +-- +-- Table: device_tokens +-- +CREATE TABLE "device_tokens" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "token" character varying(200) NOT NULL, + "register_date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "device_tokens_idx_user_id" on "device_tokens" ("user_id"); + +; +-- +-- Table: feedback +-- +CREATE TABLE "feedback" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "feedbacktext" text NOT NULL, + "app_name" character varying(255) NOT NULL, + "package_name" character varying(255) NOT NULL, + "version_code" character varying(255) NOT NULL, + "version_number" character varying(255) NOT NULL, + "actioned" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "feedback_idx_user_id" on "feedback" ("user_id"); + +; +-- +-- Table: global_user_medal_progress +-- +CREATE TABLE "global_user_medal_progress" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "total" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_user_medal_progress_idx_entity_id" on "global_user_medal_progress" ("entity_id"); +CREATE INDEX "global_user_medal_progress_idx_group_id" on "global_user_medal_progress" ("group_id"); + +; +-- +-- Table: global_user_medals +-- +CREATE TABLE "global_user_medals" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "points" integer NOT NULL, + "awarded_at" timestamp NOT NULL, + "threshold" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_user_medals_idx_entity_id" on "global_user_medals" ("entity_id"); +CREATE INDEX "global_user_medals_idx_group_id" on "global_user_medals" ("group_id"); + +; +-- +-- Table: import_lookups +-- +CREATE TABLE "import_lookups" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_lookups_idx_entity_id" on "import_lookups" ("entity_id"); +CREATE INDEX "import_lookups_idx_set_id" on "import_lookups" ("set_id"); + +; +-- +-- Table: org_user_medal_progress +-- +CREATE TABLE "org_user_medal_progress" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "total" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_user_medal_progress_idx_entity_id" on "org_user_medal_progress" ("entity_id"); +CREATE INDEX "org_user_medal_progress_idx_group_id" on "org_user_medal_progress" ("group_id"); + +; +-- +-- Table: org_user_medals +-- +CREATE TABLE "org_user_medals" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "points" integer NOT NULL, + "awarded_at" timestamp NOT NULL, + "threshold" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_user_medals_idx_entity_id" on "org_user_medals" ("entity_id"); +CREATE INDEX "org_user_medals_idx_group_id" on "org_user_medals" ("group_id"); + +; +-- +-- Table: session_tokens +-- +CREATE TABLE "session_tokens" ( + "id" serial NOT NULL, + "token" character varying(255) NOT NULL, + "user_id" integer NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "session_tokens_token" UNIQUE ("token") +); +CREATE INDEX "session_tokens_idx_user_id" on "session_tokens" ("user_id"); + +; +-- +-- Table: transaction_recurring +-- +CREATE TABLE "transaction_recurring" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "start_time" timestamp NOT NULL, + "last_updated" timestamp, + "essential" boolean DEFAULT false NOT NULL, + "distance" numeric(15), + "category_id" integer, + "recurring_period" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transaction_recurring_idx_buyer_id" on "transaction_recurring" ("buyer_id"); +CREATE INDEX "transaction_recurring_idx_category_id" on "transaction_recurring" ("category_id"); +CREATE INDEX "transaction_recurring_idx_seller_id" on "transaction_recurring" ("seller_id"); + +; +-- +-- Table: transactions_meta +-- +CREATE TABLE "transactions_meta" ( + "id" serial NOT NULL, + "transaction_id" integer NOT NULL, + "net_value" numeric(100,0) NOT NULL, + "sales_tax_value" numeric(100,0) NOT NULL, + "gross_value" numeric(100,0) NOT NULL, + "local_service" boolean DEFAULT false NOT NULL, + "regional_service" boolean DEFAULT false NOT NULL, + "national_service" boolean DEFAULT false NOT NULL, + "private_household_rebate" boolean DEFAULT false NOT NULL, + "business_tax_and_rebate" boolean DEFAULT false NOT NULL, + "stat_loc_gov" boolean DEFAULT false NOT NULL, + "central_loc_gov" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_meta_idx_transaction_id" on "transactions_meta" ("transaction_id"); + +; +-- +-- Table: entities_postcodes +-- +CREATE TABLE "entities_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("outcode", "incode", "entity_id") +); +CREATE INDEX "entities_postcodes_idx_entity_id" on "entities_postcodes" ("entity_id"); +CREATE INDEX "entities_postcodes_idx_outcode_incode" on "entities_postcodes" ("outcode", "incode"); + +; +-- +-- Table: import_values +-- +CREATE TABLE "import_values" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "user_name" character varying(255) NOT NULL, + "purchase_date" timestamp NOT NULL, + "purchase_value" character varying(255) NOT NULL, + "org_name" character varying(255) NOT NULL, + "transaction_id" integer, + "ignore_value" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_values_idx_set_id" on "import_values" ("set_id"); +CREATE INDEX "import_values_idx_transaction_id" on "import_values" ("transaction_id"); + +; +-- +-- Table: leaderboard_values +-- +CREATE TABLE "leaderboard_values" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "set_id" integer NOT NULL, + "position" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "trend" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboard_values_entity_id_set_id" UNIQUE ("entity_id", "set_id") +); +CREATE INDEX "leaderboard_values_idx_entity_id" on "leaderboard_values" ("entity_id"); +CREATE INDEX "leaderboard_values_idx_set_id" on "leaderboard_values" ("set_id"); + +; +-- +-- Table: organisations +-- +CREATE TABLE "organisations" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "street_name" text, + "town" character varying(255) NOT NULL, + "postcode" character varying(16), + "country" character varying(255), + "sector" character varying(1), + "pending" boolean DEFAULT false NOT NULL, + "is_local" boolean, + "is_fair" boolean, + "submitted_by_id" integer, + "latitude" numeric(8,5), + "longitude" numeric(8,5), + "type_id" integer, + "social_type_id" integer, + "is_anchor" boolean DEFAULT FALSE NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisations_idx_entity_id" on "organisations" ("entity_id"); +CREATE INDEX "organisations_idx_type_id" on "organisations" ("type_id"); +CREATE INDEX "organisations_idx_social_type_id" on "organisations" ("social_type_id"); + +; +-- +-- Table: transaction_category +-- +CREATE TABLE "transaction_category" ( + "category_id" integer NOT NULL, + "transaction_id" integer NOT NULL, + CONSTRAINT "transaction_category_transaction_id" UNIQUE ("transaction_id") +); +CREATE INDEX "transaction_category_idx_category_id" on "transaction_category" ("category_id"); +CREATE INDEX "transaction_category_idx_transaction_id" on "transaction_category" ("transaction_id"); + +; +-- +-- Table: transactions_external +-- +CREATE TABLE "transactions_external" ( + "id" serial NOT NULL, + "transaction_id" integer NOT NULL, + "external_reference_id" integer NOT NULL, + "external_id" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "transactions_external_external_reference_id_external_id" UNIQUE ("external_reference_id", "external_id") +); +CREATE INDEX "transactions_external_idx_external_reference_id" on "transactions_external" ("external_reference_id"); +CREATE INDEX "transactions_external_idx_transaction_id" on "transactions_external" ("transaction_id"); + +; +-- +-- Table: organisation_payroll +-- +CREATE TABLE "organisation_payroll" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "entry_period" timestamp NOT NULL, + "employee_amount" integer NOT NULL, + "local_employee_amount" integer NOT NULL, + "gross_payroll" numeric(100,0) NOT NULL, + "payroll_income_tax" numeric(100,0) NOT NULL, + "payroll_employee_ni" numeric(100,0) NOT NULL, + "payroll_employer_ni" numeric(100,0) NOT NULL, + "payroll_total_pension" numeric(100,0) NOT NULL, + "payroll_other_benefit" numeric(100,0) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisation_payroll_idx_org_id" on "organisation_payroll" ("org_id"); + +; +-- +-- Table: organisations_external +-- +CREATE TABLE "organisations_external" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "external_reference_id" integer NOT NULL, + "external_id" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisations_external_external_reference_id_external_id" UNIQUE ("external_reference_id", "external_id") +); +CREATE INDEX "organisations_external_idx_external_reference_id" on "organisations_external" ("external_reference_id"); +CREATE INDEX "organisations_external_idx_org_id" on "organisations_external" ("org_id"); + +; +-- +-- Foreign Key Definitions +-- + +; +ALTER TABLE "customers" ADD CONSTRAINT "customers_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entity_association" ADD CONSTRAINT "entity_association_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "gb_postcodes" ADD CONSTRAINT "gb_postcodes_fk_ward_id" FOREIGN KEY ("ward_id") + REFERENCES "gb_wards" ("id") DEFERRABLE; + +; +ALTER TABLE "global_medals" ADD CONSTRAINT "global_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_sets" ADD CONSTRAINT "leaderboard_sets_fk_leaderboard_id" FOREIGN KEY ("leaderboard_id") + REFERENCES "leaderboards" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_medals" ADD CONSTRAINT "org_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "users" ADD CONSTRAINT "users_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "device_tokens" ADD CONSTRAINT "device_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "feedback" ADD CONSTRAINT "feedback_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "global_user_medal_progress" ADD CONSTRAINT "global_user_medal_progress_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "global_user_medal_progress" ADD CONSTRAINT "global_user_medal_progress_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "global_user_medals" ADD CONSTRAINT "global_user_medals_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "global_user_medals" ADD CONSTRAINT "global_user_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_user_medal_progress" ADD CONSTRAINT "org_user_medal_progress_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "org_user_medal_progress" ADD CONSTRAINT "org_user_medal_progress_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_user_medals" ADD CONSTRAINT "org_user_medals_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "org_user_medals" ADD CONSTRAINT "org_user_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "session_tokens" ADD CONSTRAINT "session_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") DEFERRABLE; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions_meta" ADD CONSTRAINT "transactions_meta_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entities_postcodes" ADD CONSTRAINT "entities_postcodes_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entities_postcodes" ADD CONSTRAINT "entities_postcodes_fk_outcode_incode" FOREIGN KEY ("outcode", "incode") + REFERENCES "gb_postcodes" ("outcode", "incode") DEFERRABLE; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "leaderboard_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_type_id" FOREIGN KEY ("type_id") + REFERENCES "organisation_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_social_type_id" FOREIGN KEY ("social_type_id") + REFERENCES "organisation_social_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions_external" ADD CONSTRAINT "transactions_external_fk_external_reference_id" FOREIGN KEY ("external_reference_id") + REFERENCES "external_references" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions_external" ADD CONSTRAINT "transactions_external_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisation_payroll" ADD CONSTRAINT "organisation_payroll_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") DEFERRABLE; + +; +ALTER TABLE "organisations_external" ADD CONSTRAINT "organisations_external_fk_external_reference_id" FOREIGN KEY ("external_reference_id") + REFERENCES "external_references" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations_external" ADD CONSTRAINT "organisations_external_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; diff --git a/share/ddl/PostgreSQL/upgrade/30-31/001-auto.sql b/share/ddl/PostgreSQL/upgrade/30-31/001-auto.sql new file mode 100644 index 0000000..f72b82e --- /dev/null +++ b/share/ddl/PostgreSQL/upgrade/30-31/001-auto.sql @@ -0,0 +1,23 @@ +-- Convert schema 'share/ddl/_source/deploy/30/001-auto.yml' to 'share/ddl/_source/deploy/31/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE "device_tokens" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "token" character varying(200) NOT NULL, + "register_date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "device_tokens_idx_user_id" on "device_tokens" ("user_id"); + +; +ALTER TABLE "device_tokens" ADD CONSTRAINT "device_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; + +COMMIT; + diff --git a/share/ddl/SQLite/deploy/31/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/31/001-auto-__VERSION.sql new file mode 100644 index 0000000..b79a201 --- /dev/null +++ b/share/ddl/SQLite/deploy/31/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Wed Nov 18 22:58:25 2020 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE dbix_class_deploymenthandler_versions ( + id INTEGER PRIMARY KEY NOT NULL, + version varchar(50) NOT NULL, + ddl text, + upgrade_sql text +); +CREATE UNIQUE INDEX dbix_class_deploymenthandler_versions_version ON dbix_class_deploymenthandler_versions (version); +COMMIT; diff --git a/share/ddl/SQLite/deploy/31/001-auto.sql b/share/ddl/SQLite/deploy/31/001-auto.sql new file mode 100644 index 0000000..4ef2478 --- /dev/null +++ b/share/ddl/SQLite/deploy/31/001-auto.sql @@ -0,0 +1,481 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Wed Nov 18 22:58:25 2020 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: account_tokens +-- +CREATE TABLE account_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + name text NOT NULL, + used integer NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX account_tokens_name ON account_tokens (name); +-- +-- Table: category +-- +CREATE TABLE category ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + line_icon varchar(255) +); +CREATE UNIQUE INDEX category_name ON category (name); +-- +-- Table: entities +-- +CREATE TABLE entities ( + id INTEGER PRIMARY KEY NOT NULL, + type varchar(255) NOT NULL +); +-- +-- Table: external_references +-- +CREATE TABLE external_references ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX external_references_name ON external_references (name); +-- +-- Table: gb_wards +-- +CREATE TABLE gb_wards ( + id INTEGER PRIMARY KEY NOT NULL, + ward varchar(100) NOT NULL +); +-- +-- Table: global_medal_group +-- +CREATE TABLE global_medal_group ( + id INTEGER PRIMARY KEY NOT NULL, + group_name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX global_medal_group_group_name ON global_medal_group (group_name); +-- +-- Table: import_sets +-- +CREATE TABLE import_sets ( + id INTEGER PRIMARY KEY NOT NULL, + date datetime NOT NULL +); +-- +-- Table: leaderboards +-- +CREATE TABLE leaderboards ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + type varchar(255) NOT NULL +); +CREATE UNIQUE INDEX leaderboards_type ON leaderboards (type); +-- +-- Table: org_medal_group +-- +CREATE TABLE org_medal_group ( + id INTEGER PRIMARY KEY NOT NULL, + group_name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX org_medal_group_group_name ON org_medal_group (group_name); +-- +-- Table: organisation_social_types +-- +CREATE TABLE organisation_social_types ( + id INTEGER PRIMARY KEY NOT NULL, + key varchar(255) NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX organisation_social_types_key ON organisation_social_types (key); +-- +-- Table: organisation_types +-- +CREATE TABLE organisation_types ( + id INTEGER PRIMARY KEY NOT NULL, + key varchar(255) NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX organisation_types_key ON organisation_types (key); +-- +-- Table: customers +-- +CREATE TABLE customers ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + display_name varchar(255) NOT NULL, + full_name varchar(255) NOT NULL, + year_of_birth integer NOT NULL, + postcode varchar(16) NOT NULL, + latitude decimal(5,2), + longitude decimal(5,2), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX customers_idx_entity_id ON customers (entity_id); +-- +-- Table: entity_association +-- +CREATE TABLE entity_association ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + lis boolean, + esta boolean, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX entity_association_idx_entity_id ON entity_association (entity_id); +-- +-- Table: gb_postcodes +-- +CREATE TABLE gb_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL DEFAULT '', + latitude decimal(7,5), + longitude decimal(7,5), + ward_id integer, + PRIMARY KEY (outcode, incode), + FOREIGN KEY (ward_id) REFERENCES gb_wards(id) +); +CREATE INDEX gb_postcodes_idx_ward_id ON gb_postcodes (ward_id); +-- +-- Table: global_medals +-- +CREATE TABLE global_medals ( + id INTEGER PRIMARY KEY NOT NULL, + group_id integer NOT NULL, + threshold integer NOT NULL, + points integer NOT NULL, + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_medals_idx_group_id ON global_medals (group_id); +-- +-- Table: leaderboard_sets +-- +CREATE TABLE leaderboard_sets ( + id INTEGER PRIMARY KEY NOT NULL, + leaderboard_id integer NOT NULL, + date datetime NOT NULL, + FOREIGN KEY (leaderboard_id) REFERENCES leaderboards(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_sets_idx_leaderboard_id ON leaderboard_sets (leaderboard_id); +-- +-- Table: org_medals +-- +CREATE TABLE org_medals ( + id INTEGER PRIMARY KEY NOT NULL, + group_id integer NOT NULL, + threshold integer NOT NULL, + points integer NOT NULL, + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_medals_idx_group_id ON org_medals (group_id); +-- +-- Table: transactions +-- +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + essential boolean NOT NULL DEFAULT false, + distance numeric(15), + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transactions_idx_buyer_id ON transactions (buyer_id); +CREATE INDEX transactions_idx_seller_id ON transactions (seller_id); +-- +-- Table: users +-- +CREATE TABLE users ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + email text NOT NULL, + join_date datetime NOT NULL, + password varchar(100) NOT NULL, + is_admin boolean NOT NULL DEFAULT false, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX users_idx_entity_id ON users (entity_id); +CREATE UNIQUE INDEX users_email ON users (email); +-- +-- Table: device_tokens +-- +CREATE TABLE device_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + token varchar(200) NOT NULL, + register_date datetime NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX device_tokens_idx_user_id ON device_tokens (user_id); +-- +-- Table: feedback +-- +CREATE TABLE feedback ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + submitted_at datetime NOT NULL, + feedbacktext text NOT NULL, + app_name varchar(255) NOT NULL, + package_name varchar(255) NOT NULL, + version_code varchar(255) NOT NULL, + version_number varchar(255) NOT NULL, + actioned boolean NOT NULL DEFAULT false, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX feedback_idx_user_id ON feedback (user_id); +-- +-- Table: global_user_medal_progress +-- +CREATE TABLE global_user_medal_progress ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + total integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_user_medal_progress_idx_entity_id ON global_user_medal_progress (entity_id); +CREATE INDEX global_user_medal_progress_idx_group_id ON global_user_medal_progress (group_id); +-- +-- Table: global_user_medals +-- +CREATE TABLE global_user_medals ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + points integer NOT NULL, + awarded_at datetime NOT NULL, + threshold integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_user_medals_idx_entity_id ON global_user_medals (entity_id); +CREATE INDEX global_user_medals_idx_group_id ON global_user_medals (group_id); +-- +-- Table: import_lookups +-- +CREATE TABLE import_lookups ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + name varchar(255) NOT NULL, + entity_id integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_lookups_idx_entity_id ON import_lookups (entity_id); +CREATE INDEX import_lookups_idx_set_id ON import_lookups (set_id); +-- +-- Table: org_user_medal_progress +-- +CREATE TABLE org_user_medal_progress ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + total integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_user_medal_progress_idx_entity_id ON org_user_medal_progress (entity_id); +CREATE INDEX org_user_medal_progress_idx_group_id ON org_user_medal_progress (group_id); +-- +-- Table: org_user_medals +-- +CREATE TABLE org_user_medals ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + points integer NOT NULL, + awarded_at datetime NOT NULL, + threshold integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_user_medals_idx_entity_id ON org_user_medals (entity_id); +CREATE INDEX org_user_medals_idx_group_id ON org_user_medals (group_id); +-- +-- Table: session_tokens +-- +CREATE TABLE session_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + token varchar(255) NOT NULL, + user_id integer NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX session_tokens_idx_user_id ON session_tokens (user_id); +CREATE UNIQUE INDEX session_tokens_token ON session_tokens (token); +-- +-- Table: transaction_recurring +-- +CREATE TABLE transaction_recurring ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + start_time datetime NOT NULL, + last_updated datetime, + essential boolean NOT NULL DEFAULT false, + distance numeric(15), + category_id integer, + recurring_period varchar(255) NOT NULL, + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (category_id) REFERENCES category(id), + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transaction_recurring_idx_buyer_id ON transaction_recurring (buyer_id); +CREATE INDEX transaction_recurring_idx_category_id ON transaction_recurring (category_id); +CREATE INDEX transaction_recurring_idx_seller_id ON transaction_recurring (seller_id); +-- +-- Table: transactions_meta +-- +CREATE TABLE transactions_meta ( + id INTEGER PRIMARY KEY NOT NULL, + transaction_id integer NOT NULL, + net_value numeric(100,0) NOT NULL, + sales_tax_value numeric(100,0) NOT NULL, + gross_value numeric(100,0) NOT NULL, + local_service boolean NOT NULL DEFAULT false, + regional_service boolean NOT NULL DEFAULT false, + national_service boolean NOT NULL DEFAULT false, + private_household_rebate boolean NOT NULL DEFAULT false, + business_tax_and_rebate boolean NOT NULL DEFAULT false, + stat_loc_gov boolean NOT NULL DEFAULT false, + central_loc_gov boolean NOT NULL DEFAULT false, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); +CREATE INDEX transactions_meta_idx_transaction_id ON transactions_meta (transaction_id); +-- +-- Table: entities_postcodes +-- +CREATE TABLE entities_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL, + entity_id integer NOT NULL, + PRIMARY KEY (outcode, incode, entity_id), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE, + FOREIGN KEY (outcode, incode) REFERENCES gb_postcodes(outcode, incode) +); +CREATE INDEX entities_postcodes_idx_entity_id ON entities_postcodes (entity_id); +CREATE INDEX entities_postcodes_idx_outcode_incode ON entities_postcodes (outcode, incode); +-- +-- Table: import_values +-- +CREATE TABLE import_values ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + user_name varchar(255) NOT NULL, + purchase_date datetime NOT NULL, + purchase_value varchar(255) NOT NULL, + org_name varchar(255) NOT NULL, + transaction_id integer, + ignore_value boolean NOT NULL DEFAULT false, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_values_idx_set_id ON import_values (set_id); +CREATE INDEX import_values_idx_transaction_id ON import_values (transaction_id); +-- +-- Table: leaderboard_values +-- +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_values_idx_entity_id ON leaderboard_values (entity_id); +CREATE INDEX leaderboard_values_idx_set_id ON leaderboard_values (set_id); +CREATE UNIQUE INDEX leaderboard_values_entity_id_set_id ON leaderboard_values (entity_id, set_id); +-- +-- Table: organisations +-- +CREATE TABLE organisations ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + name varchar(255) NOT NULL, + street_name text, + town varchar(255) NOT NULL, + postcode varchar(16), + country varchar(255), + sector varchar(1), + pending boolean NOT NULL DEFAULT false, + is_local boolean, + is_fair boolean, + submitted_by_id integer, + latitude decimal(8,5), + longitude decimal(8,5), + type_id integer, + social_type_id integer, + is_anchor boolean NOT NULL DEFAULT FALSE, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE, + FOREIGN KEY (type_id) REFERENCES organisation_types(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (social_type_id) REFERENCES organisation_social_types(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX organisations_idx_entity_id ON organisations (entity_id); +CREATE INDEX organisations_idx_type_id ON organisations (type_id); +CREATE INDEX organisations_idx_social_type_id ON organisations (social_type_id); +-- +-- Table: transaction_category +-- +CREATE TABLE transaction_category ( + category_id integer NOT NULL, + transaction_id integer NOT NULL, + FOREIGN KEY (category_id) REFERENCES category(id) ON DELETE CASCADE, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); +CREATE INDEX transaction_category_idx_category_id ON transaction_category (category_id); +CREATE INDEX transaction_category_idx_transaction_id ON transaction_category (transaction_id); +CREATE UNIQUE INDEX transaction_category_transaction_id ON transaction_category (transaction_id); +-- +-- Table: transactions_external +-- +CREATE TABLE transactions_external ( + id INTEGER PRIMARY KEY NOT NULL, + transaction_id integer NOT NULL, + external_reference_id integer NOT NULL, + external_id varchar(255) NOT NULL, + FOREIGN KEY (external_reference_id) REFERENCES external_references(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX transactions_external_idx_external_reference_id ON transactions_external (external_reference_id); +CREATE INDEX transactions_external_idx_transaction_id ON transactions_external (transaction_id); +CREATE UNIQUE INDEX transactions_external_external_reference_id_external_id ON transactions_external (external_reference_id, external_id); +-- +-- Table: organisation_payroll +-- +CREATE TABLE organisation_payroll ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + submitted_at datetime NOT NULL, + entry_period datetime NOT NULL, + employee_amount integer NOT NULL, + local_employee_amount integer NOT NULL, + gross_payroll numeric(100,0) NOT NULL, + payroll_income_tax numeric(100,0) NOT NULL, + payroll_employee_ni numeric(100,0) NOT NULL, + payroll_employer_ni numeric(100,0) NOT NULL, + payroll_total_pension numeric(100,0) NOT NULL, + payroll_other_benefit numeric(100,0) NOT NULL, + FOREIGN KEY (org_id) REFERENCES organisations(id) +); +CREATE INDEX organisation_payroll_idx_org_id ON organisation_payroll (org_id); +-- +-- Table: organisations_external +-- +CREATE TABLE organisations_external ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + external_reference_id integer NOT NULL, + external_id varchar(255) NOT NULL, + FOREIGN KEY (external_reference_id) REFERENCES external_references(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (org_id) REFERENCES organisations(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX organisations_external_idx_external_reference_id ON organisations_external (external_reference_id); +CREATE INDEX organisations_external_idx_org_id ON organisations_external (org_id); +CREATE UNIQUE INDEX organisations_external_external_reference_id_external_id ON organisations_external (external_reference_id, external_id); +COMMIT; diff --git a/share/ddl/SQLite/upgrade/30-31/001-auto.sql b/share/ddl/SQLite/upgrade/30-31/001-auto.sql new file mode 100644 index 0000000..4c814f4 --- /dev/null +++ b/share/ddl/SQLite/upgrade/30-31/001-auto.sql @@ -0,0 +1,21 @@ +-- Convert schema 'share/ddl/_source/deploy/30/001-auto.yml' to 'share/ddl/_source/deploy/31/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE device_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + token varchar(200) NOT NULL, + register_date datetime NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); + +; +CREATE INDEX device_tokens_idx_user_id ON device_tokens (user_id); + +; + +COMMIT; + diff --git a/share/ddl/_source/deploy/31/001-auto-__VERSION.yml b/share/ddl/_source/deploy/31/001-auto-__VERSION.yml new file mode 100644 index 0000000..487f2d7 --- /dev/null +++ b/share/ddl/_source/deploy/31/001-auto-__VERSION.yml @@ -0,0 +1,91 @@ +--- +schema: + procedures: {} + tables: + dbix_class_deploymenthandler_versions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - version + match_type: '' + name: dbix_class_deploymenthandler_versions_version + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + ddl: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ddl + order: 3 + size: + - 0 + id: + data_type: int + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + upgrade_sql: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: upgrade_sql + order: 4 + size: + - 0 + version: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: version + order: 2 + size: + - 50 + indices: [] + name: dbix_class_deploymenthandler_versions + options: [] + order: 1 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - __VERSION + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 1.62 diff --git a/share/ddl/_source/deploy/31/001-auto.yml b/share/ddl/_source/deploy/31/001-auto.yml new file mode 100644 index 0000000..89151e6 --- /dev/null +++ b/share/ddl/_source/deploy/31/001-auto.yml @@ -0,0 +1,3629 @@ +--- +schema: + procedures: {} + tables: + account_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: account_tokens_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 0 + used: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: used + order: 3 + size: + - 0 + indices: [] + name: account_tokens + options: [] + order: 1 + category: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: category_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + line_icon: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: line_icon + order: 3 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 255 + indices: [] + name: category + options: [] + order: 2 + customers: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: customers_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + display_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: display_name + order: 3 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + full_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 4 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 7 + size: + - 5 + - 2 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 8 + size: + - 5 + - 2 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + year_of_birth: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: year_of_birth + order: 5 + size: + - 0 + indices: + - fields: + - entity_id + name: customers_idx_entity_id + options: [] + type: NORMAL + name: customers + options: [] + order: 12 + device_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: device_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + register_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: register_date + order: 4 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: token + order: 3 + size: + - 200 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + indices: + - fields: + - user_id + name: device_tokens_idx_user_id + options: [] + type: NORMAL + name: device_tokens + options: [] + order: 20 + entities: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: type + order: 2 + size: + - 255 + indices: [] + name: entities + options: [] + order: 3 + entities_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + - entity_id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entities_postcodes_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: entities_postcodes_fk_outcode_incode + on_delete: '' + on_update: '' + options: [] + reference_fields: + - outcode + - incode + reference_table: gb_postcodes + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: entity_id + order: 3 + size: + - 0 + incode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + indices: + - fields: + - entity_id + name: entities_postcodes_idx_entity_id + options: [] + type: NORMAL + - fields: + - outcode + - incode + name: entities_postcodes_idx_outcode_incode + options: [] + type: NORMAL + name: entities_postcodes + options: [] + order: 30 + entity_association: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entity_association_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + esta: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: esta + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + lis: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: lis + order: 3 + size: + - 0 + indices: + - fields: + - entity_id + name: entity_association_idx_entity_id + options: [] + type: NORMAL + name: entity_association + options: [] + order: 13 + external_references: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: external_references_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 255 + indices: [] + name: external_references + options: [] + order: 4 + feedback: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: feedback_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + actioned: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: actioned + order: 9 + size: + - 0 + app_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: app_name + order: 5 + size: + - 255 + feedbacktext: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: feedbacktext + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + package_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: package_name + order: 6 + size: + - 255 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + version_code: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_code + order: 7 + size: + - 255 + version_number: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_number + order: 8 + size: + - 255 + indices: + - fields: + - user_id + name: feedback_idx_user_id + options: [] + type: NORMAL + name: feedback + options: [] + order: 21 + gb_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - ward_id + match_type: '' + name: gb_postcodes_fk_ward_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: gb_wards + type: FOREIGN KEY + fields: + incode: + data_type: char + default_value: '' + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 3 + size: + - 7 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 4 + size: + - 7 + - 5 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + ward_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ward_id + order: 5 + size: + - 0 + indices: + - fields: + - ward_id + name: gb_postcodes_idx_ward_id + options: [] + type: NORMAL + name: gb_postcodes + options: [] + order: 14 + gb_wards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ward: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ward + order: 2 + size: + - 100 + indices: [] + name: gb_wards + options: [] + order: 5 + global_medal_group: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - group_name + match_type: '' + name: global_medal_group_group_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + group_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: group_name + order: 2 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: global_medal_group + options: [] + order: 6 + global_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 3 + size: + - 0 + indices: + - fields: + - group_id + name: global_medals_idx_group_id + options: [] + type: NORMAL + name: global_medals + options: [] + order: 15 + global_user_medal_progress: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: global_user_medal_progress_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_user_medal_progress_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + total: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: total + order: 4 + size: + - 0 + indices: + - fields: + - entity_id + name: global_user_medal_progress_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: global_user_medal_progress_idx_group_id + options: [] + type: NORMAL + name: global_user_medal_progress + options: [] + order: 22 + global_user_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: global_user_medals_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_user_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + awarded_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: awarded_at + order: 5 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 6 + size: + - 0 + indices: + - fields: + - entity_id + name: global_user_medals_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: global_user_medals_idx_group_id + options: [] + type: NORMAL + name: global_user_medals + options: [] + order: 23 + import_lookups: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: import_lookups_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_lookups_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + indices: + - fields: + - entity_id + name: import_lookups_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: import_lookups_idx_set_id + options: [] + type: NORMAL + name: import_lookups + options: [] + order: 24 + import_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: import_sets + options: [] + order: 7 + import_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: import_values_fk_transaction_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ignore_value: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ignore_value + order: 8 + size: + - 0 + org_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_name + order: 6 + size: + - 255 + purchase_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_date + order: 4 + size: + - 0 + purchase_value: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_value + order: 5 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 7 + size: + - 0 + user_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_name + order: 3 + size: + - 255 + indices: + - fields: + - set_id + name: import_values_idx_set_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: import_values_idx_transaction_id + options: [] + type: NORMAL + name: import_values + options: [] + order: 31 + leaderboard_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - leaderboard_id + match_type: '' + name: leaderboard_sets_fk_leaderboard_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboards + type: FOREIGN KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + leaderboard_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: leaderboard_id + order: 2 + size: + - 0 + indices: + - fields: + - leaderboard_id + name: leaderboard_sets_idx_leaderboard_id + options: [] + type: NORMAL + name: leaderboard_sets + options: [] + order: 16 + leaderboard_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + - set_id + match_type: '' + name: leaderboard_values_entity_id_set_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - entity_id + match_type: '' + name: leaderboard_values_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: leaderboard_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboard_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + position: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: position + order: 4 + size: + - 0 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: set_id + order: 3 + size: + - 0 + trend: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: trend + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 5 + size: + - 100 + - 0 + indices: + - fields: + - entity_id + name: leaderboard_values_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: leaderboard_values_idx_set_id + options: [] + type: NORMAL + name: leaderboard_values + options: [] + order: 32 + leaderboards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - type + match_type: '' + name: leaderboards_type + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 255 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: type + order: 3 + size: + - 255 + indices: [] + name: leaderboards + options: [] + order: 8 + org_medal_group: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - group_name + match_type: '' + name: org_medal_group_group_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + group_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: group_name + order: 2 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: org_medal_group + options: [] + order: 9 + org_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 3 + size: + - 0 + indices: + - fields: + - group_id + name: org_medals_idx_group_id + options: [] + type: NORMAL + name: org_medals + options: [] + order: 17 + org_user_medal_progress: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: org_user_medal_progress_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_user_medal_progress_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + total: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: total + order: 4 + size: + - 0 + indices: + - fields: + - entity_id + name: org_user_medal_progress_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: org_user_medal_progress_idx_group_id + options: [] + type: NORMAL + name: org_user_medal_progress + options: [] + order: 25 + org_user_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: org_user_medals_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_user_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + awarded_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: awarded_at + order: 5 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 6 + size: + - 0 + indices: + - fields: + - entity_id + name: org_user_medals_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: org_user_medals_idx_group_id + options: [] + type: NORMAL + name: org_user_medals + options: [] + order: 26 + organisation_payroll: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisation_payroll_fk_org_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: employee_amount + order: 5 + size: + - 0 + entry_period: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entry_period + order: 4 + size: + - 0 + gross_payroll: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_payroll + order: 7 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_employee_amount + order: 6 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + payroll_employee_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employee_ni + order: 9 + size: + - 100 + - 0 + payroll_employer_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employer_ni + order: 10 + size: + - 100 + - 0 + payroll_income_tax: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_income_tax + order: 8 + size: + - 100 + - 0 + payroll_other_benefit: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_other_benefit + order: 12 + size: + - 100 + - 0 + payroll_total_pension: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_total_pension + order: 11 + size: + - 100 + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + indices: + - fields: + - org_id + name: organisation_payroll_idx_org_id + options: [] + type: NORMAL + name: organisation_payroll + options: [] + order: 36 + organisation_social_types: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - key + match_type: '' + name: organisation_social_types_key + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + key: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: key + order: 2 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + indices: [] + name: organisation_social_types + options: [] + order: 10 + organisation_types: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - key + match_type: '' + name: organisation_types_key + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + key: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: key + order: 2 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + indices: [] + name: organisation_types + options: [] + order: 11 + organisations: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: organisations_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - type_id + match_type: '' + name: organisations_fk_type_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisation_types + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - social_type_id + match_type: '' + name: organisations_fk_social_type_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisation_social_types + type: FOREIGN KEY + fields: + country: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: country + order: 7 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_anchor: + data_type: boolean + default_value: !!perl/ref + =: FALSE + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_anchor + order: 17 + size: + - 0 + is_fair: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_fair + order: 11 + size: + - 0 + is_local: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_local + order: 10 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 13 + size: + - 8 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 14 + size: + - 8 + - 5 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + pending: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: pending + order: 9 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + sector: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: sector + order: 8 + size: + - 1 + social_type_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: social_type_id + order: 16 + size: + - 0 + street_name: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: street_name + order: 4 + size: + - 0 + submitted_by_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: submitted_by_id + order: 12 + size: + - 0 + town: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: town + order: 5 + size: + - 255 + type_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: type_id + order: 15 + size: + - 0 + indices: + - fields: + - entity_id + name: organisations_idx_entity_id + options: [] + type: NORMAL + - fields: + - type_id + name: organisations_idx_type_id + options: [] + type: NORMAL + - fields: + - social_type_id + name: organisations_idx_social_type_id + options: [] + type: NORMAL + name: organisations + options: [] + order: 33 + organisations_external: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - external_reference_id + - external_id + match_type: '' + name: organisations_external_external_reference_id_external_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - external_reference_id + match_type: '' + name: organisations_external_fk_external_reference_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: external_references + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisations_external_fk_org_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + external_id: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_id + order: 4 + size: + - 255 + external_reference_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_reference_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + indices: + - fields: + - external_reference_id + name: organisations_external_idx_external_reference_id + options: [] + type: NORMAL + - fields: + - org_id + name: organisations_external_idx_org_id + options: [] + type: NORMAL + name: organisations_external + options: [] + order: 37 + session_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - token + match_type: '' + name: session_tokens_token + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: session_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: token + order: 2 + size: + - 255 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 3 + size: + - 0 + indices: + - fields: + - user_id + name: session_tokens_idx_user_id + options: [] + type: NORMAL + name: session_tokens + options: [] + order: 27 + transaction_category: + constraints: + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_transaction_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - category_id + match_type: '' + name: transaction_category_fk_category_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: category + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_fk_transaction_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + category_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: category_id + order: 1 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - category_id + name: transaction_category_idx_category_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: transaction_category_idx_transaction_id + options: [] + type: NORMAL + name: transaction_category + options: [] + order: 34 + transaction_recurring: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transaction_recurring_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - category_id + match_type: '' + name: transaction_recurring_fk_category_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: category + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transaction_recurring_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + category_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: category_id + order: 9 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 8 + size: + - 15 + essential: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: essential + order: 7 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + last_updated: + data_type: datetime + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: last_updated + order: 6 + size: + - 0 + recurring_period: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: recurring_period + order: 10 + size: + - 255 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + start_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: start_time + order: 5 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transaction_recurring_idx_buyer_id + options: [] + type: NORMAL + - fields: + - category_id + name: transaction_recurring_idx_category_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transaction_recurring_idx_seller_id + options: [] + type: NORMAL + name: transaction_recurring + options: [] + order: 28 + transactions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transactions_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transactions_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 9 + size: + - 15 + essential: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: essential + order: 8 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + proof_image: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: proof_image + order: 5 + size: + - 0 + purchase_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_time + order: 7 + size: + - 0 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transactions_idx_buyer_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transactions_idx_seller_id + options: [] + type: NORMAL + name: transactions + options: [] + order: 18 + transactions_external: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - external_reference_id + - external_id + match_type: '' + name: transactions_external_external_reference_id_external_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - external_reference_id + match_type: '' + name: transactions_external_fk_external_reference_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: external_references + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transactions_external_fk_transaction_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + external_id: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_id + order: 4 + size: + - 255 + external_reference_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_reference_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - external_reference_id + name: transactions_external_idx_external_reference_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: transactions_external_idx_transaction_id + options: [] + type: NORMAL + name: transactions_external + options: [] + order: 35 + transactions_meta: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transactions_meta_fk_transaction_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + business_tax_and_rebate: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: business_tax_and_rebate + order: 10 + size: + - 0 + central_loc_gov: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: central_loc_gov + order: 12 + size: + - 0 + gross_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_value + order: 5 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_service + order: 6 + size: + - 0 + national_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: national_service + order: 8 + size: + - 0 + net_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: net_value + order: 3 + size: + - 100 + - 0 + private_household_rebate: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: private_household_rebate + order: 9 + size: + - 0 + regional_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: regional_service + order: 7 + size: + - 0 + sales_tax_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: sales_tax_value + order: 4 + size: + - 100 + - 0 + stat_loc_gov: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: stat_loc_gov + order: 11 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - transaction_id + name: transactions_meta_idx_transaction_id + options: [] + type: NORMAL + name: transactions_meta + options: [] + order: 29 + users: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: users_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: users_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 3 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_admin: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_admin + order: 6 + size: + - 0 + join_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: join_date + order: 4 + size: + - 0 + password: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: password + order: 5 + size: + - 100 + indices: + - fields: + - entity_id + name: users_idx_entity_id + options: [] + type: NORMAL + name: users + options: [] + order: 19 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - AccountToken + - Category + - Customer + - DeviceToken + - Entity + - EntityAssociation + - EntityPostcode + - ExternalReference + - Feedback + - GbPostcode + - GbWard + - GlobalMedalGroup + - GlobalMedals + - GlobalUserMedalProgress + - GlobalUserMedals + - ImportLookup + - ImportSet + - ImportValue + - Leaderboard + - LeaderboardSet + - LeaderboardValue + - OrgMedalGroup + - OrgMedals + - OrgUserMedalProgress + - OrgUserMedals + - Organisation + - OrganisationExternal + - OrganisationPayroll + - OrganisationSocialType + - OrganisationType + - SessionToken + - Transaction + - TransactionCategory + - TransactionExternal + - TransactionMeta + - TransactionRecurring + - User + - ViewQuantisedTransactionCategoryPg + - ViewQuantisedTransactionCategorySQLite + - ViewQuantisedTransactionPg + - ViewQuantisedTransactionSQLite + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 1.62 From 350113807473d32c2baae475cda2ae1397aa941a Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Wed, 18 Nov 2020 23:01:18 +0000 Subject: [PATCH 257/289] Add db upgrade step --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index abc24f6..a6d9c6e 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ needed initially. To upgrade the database after making changes to commit: +1. Increment the `$VERSION` number in `lib/Pear/LocalLoop/Schema.pm` 1. `./script/deploy_db write_ddl -c 'dbi:SQLite:dbname=foodloop.db'` 1. `./script/deploy_db upgrade -c 'dbi:SQLite:dbname=foodloop.db'` From 0d4202562fde788c1cee949b534ff1d8d3dc1909 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Sat, 28 Nov 2020 14:26:59 +0000 Subject: [PATCH 258/289] Make minor README edits --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a6d9c6e..98c0610 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ needed initially. --with-feature=sqlite \ --with-feature=codepoint-open ``` + - See [Troubleshooting](#troubleshooting) if you encounter difficulties. 1. Install the database: - `./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db'` 1. Set up the development users: @@ -130,13 +131,14 @@ To redo leaderboards: ## ‘Can't write to /usr/local/share/perl/5.30.0 and /usr/local/bin: Installing modules to /home//perl5’ when running `cpanm` commands -Intall `local::lib` by running the following commands: +Install `local::lib` by running the following commands: ``` cpanm --local-lib=~/perl5 local::lib && eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib) ``` -NB: You must run this in each Terminal window; I don't know why. +You will have to do every time you open a new Terminal window. +To make it permanent, follow [these steps](https://www.cpan.org/modules/by-module/lib/local-lib-2.000018.readme). ## ‘Can't load application from file "/script/pear-local_loop": Can't locate Data/UUID.pm in @INC (you may need to install the DATA::UUID module)’ when running server From 9d4c736d95874402f2fe0dc057d19df3881407b8 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Sat, 28 Nov 2020 19:53:19 +0000 Subject: [PATCH 259/289] Add device token management and server connection detection --- README.md | 3 +- cpanfile | 4 + lib/Pear/LocalLoop.pm | 2 + lib/Pear/LocalLoop/Controller/Api/Auth.pm | 12 + .../LocalLoop/Controller/Api/Sendmessage.pm | 10 +- lib/Pear/LocalLoop/Schema.pm | 2 +- .../deploy/32/001-auto-__VERSION.sql | 18 + share/ddl/PostgreSQL/deploy/32/001-auto.sql | 717 ++++ .../ddl/PostgreSQL/upgrade/31-32/001-auto.sql | 5 + .../SQLite/deploy/32/001-auto-__VERSION.sql | 18 + share/ddl/SQLite/deploy/32/001-auto.sql | 481 +++ share/ddl/SQLite/upgrade/31-32/001-auto.sql | 5 + .../_source/deploy/32/001-auto-__VERSION.yml | 91 + share/ddl/_source/deploy/32/001-auto.yml | 3629 +++++++++++++++++ 14 files changed, 4990 insertions(+), 7 deletions(-) create mode 100644 share/ddl/PostgreSQL/deploy/32/001-auto-__VERSION.sql create mode 100644 share/ddl/PostgreSQL/deploy/32/001-auto.sql create mode 100644 share/ddl/PostgreSQL/upgrade/31-32/001-auto.sql create mode 100644 share/ddl/SQLite/deploy/32/001-auto-__VERSION.sql create mode 100644 share/ddl/SQLite/deploy/32/001-auto.sql create mode 100644 share/ddl/SQLite/upgrade/31-32/001-auto.sql create mode 100644 share/ddl/_source/deploy/32/001-auto-__VERSION.yml create mode 100644 share/ddl/_source/deploy/32/001-auto.yml diff --git a/README.md b/README.md index 98c0610..8cf1488 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,8 @@ needed initially. - `./script/pear-local_loop minion worker` 1. Import ward data (see [instructions](#importing-ward-data) above) 1. Set up postcodes (see [instructions](#setting-up-entity-postcodes) above) -1. Create an `environment.dev.ts` file in `src/environments` with your API keys +1. Set up your `pear-local_loop.⟨environment⟩.conf` file in the project root +1. Ensure you have a copy of the FCM service user credentials saved in the project root (`localspend-47012.json`) 1. Start the application: - `morbo script/pear-local_loop -l http://*:3000` - You can modify the host and port as needed. diff --git a/cpanfile b/cpanfile index 76dbb29..041c680 100644 --- a/cpanfile +++ b/cpanfile @@ -3,6 +3,10 @@ requires 'Mojolicious::Plugin::Authentication'; requires 'Data::UUID'; requires 'Devel::Dwarn'; requires 'Mojo::JSON'; +requires 'LWP::UserAgent'; +requires 'Mojo::JWT'; +requires 'Mojo::File'; +requires 'Crypt::OpenSSL::RSA'; requires 'Email::Valid'; requires 'Geo::UK::Postcode::Regex' => '0.017'; requires 'Authen::Passphrase::BlowfishCrypt'; diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index c665cd6..51ccba5 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -137,11 +137,13 @@ sub startup { # Always available api routes my $api_public = $api_public_get->under('/')->to('api-auth#check_json'); + $api_public->post('/test-connection')->to('api-auth#test_connection'); $api_public->post('/login')->to('api-auth#post_login'); $api_public->post('/register')->to('api-register#post_register'); $api_public->post('/logout')->to('api-auth#post_logout'); $api_public->post('/feedback')->to('api-feedback#post_feedback'); $api_public->post('/add-device-token')->to('api-devices#add_token'); + $api_public->post('/get-device-tokens')->to('api-devices#get_tokens'); $api_public->post('/send-message')->to('api-sendmessage#post_message'); # Private, must be authenticated api routes diff --git a/lib/Pear/LocalLoop/Controller/Api/Auth.pm b/lib/Pear/LocalLoop/Controller/Api/Auth.pm index 6995e2f..2f44b10 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Auth.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Auth.pm @@ -60,6 +60,18 @@ sub auth { return 0; } +sub test_connection { + my $c = shift; + + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Database connection successful', + }, + status => 200, + ); +} + sub post_login { my $c = shift; diff --git a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm index bb6becd..a758047 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm @@ -10,10 +10,12 @@ use Carp; has error_messages => sub { return { devicetoken => { - required => { message => 'Device token is required or not registered', status => 400 }, + required => { message => 'Device token is required', status => 400 }, + in_resultset => { message => 'Device token not found', status => 400 }, }, sender => { required => { message => 'Sender name is required', status => 400 }, + in_resultset => { message => 'Sender org not found', status => 400 }, }, messagetext => { required => { message => 'Message is required', status => 400 }, @@ -70,10 +72,8 @@ sub post_message { my $validation = $c->validation; $validation->input( $c->stash->{api_json} ); - my $user_rs = $c->schema->resultset('User'); - - $validation->required('devicetoken'); - $validation->required('sender'); + $validation->required('devicetoken')->in_resultset('token', $c->schema->resultset('DeviceToken')); + $validation->required('sender')->in_resultset('name', $c->schema->resultset('Organisation')); $validation->required('messagetext'); return $c->api_validation_error if $validation->has_error; diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index f3add3a..59fec01 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -6,7 +6,7 @@ use warnings; use base 'DBIx::Class::Schema'; -our $VERSION = 31; +our $VERSION = 32; __PACKAGE__->load_namespaces; diff --git a/share/ddl/PostgreSQL/deploy/32/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/32/001-auto-__VERSION.sql new file mode 100644 index 0000000..b54c92f --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/32/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Sat Nov 28 14:26:03 2020 +-- +; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE "dbix_class_deploymenthandler_versions" ( + "id" serial NOT NULL, + "version" character varying(50) NOT NULL, + "ddl" text, + "upgrade_sql" text, + PRIMARY KEY ("id"), + CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version") +); + +; diff --git a/share/ddl/PostgreSQL/deploy/32/001-auto.sql b/share/ddl/PostgreSQL/deploy/32/001-auto.sql new file mode 100644 index 0000000..6f3c3f3 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/32/001-auto.sql @@ -0,0 +1,717 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Sat Nov 28 14:26:03 2020 +-- +; +-- +-- Table: account_tokens +-- +CREATE TABLE "account_tokens" ( + "id" serial NOT NULL, + "name" text NOT NULL, + "used" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "account_tokens_name" UNIQUE ("name") +); + +; +-- +-- Table: category +-- +CREATE TABLE "category" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "line_icon" character varying(255), + PRIMARY KEY ("id"), + CONSTRAINT "category_name" UNIQUE ("name") +); + +; +-- +-- Table: entities +-- +CREATE TABLE "entities" ( + "id" serial NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: external_references +-- +CREATE TABLE "external_references" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "external_references_name" UNIQUE ("name") +); + +; +-- +-- Table: gb_wards +-- +CREATE TABLE "gb_wards" ( + "id" serial NOT NULL, + "ward" character varying(100) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: global_medal_group +-- +CREATE TABLE "global_medal_group" ( + "id" serial NOT NULL, + "group_name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "global_medal_group_group_name" UNIQUE ("group_name") +); + +; +-- +-- Table: import_sets +-- +CREATE TABLE "import_sets" ( + "id" serial NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: leaderboards +-- +CREATE TABLE "leaderboards" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboards_type" UNIQUE ("type") +); + +; +-- +-- Table: org_medal_group +-- +CREATE TABLE "org_medal_group" ( + "id" serial NOT NULL, + "group_name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "org_medal_group_group_name" UNIQUE ("group_name") +); + +; +-- +-- Table: organisation_social_types +-- +CREATE TABLE "organisation_social_types" ( + "id" serial NOT NULL, + "key" character varying(255) NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisation_social_types_key" UNIQUE ("key") +); + +; +-- +-- Table: organisation_types +-- +CREATE TABLE "organisation_types" ( + "id" serial NOT NULL, + "key" character varying(255) NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisation_types_key" UNIQUE ("key") +); + +; +-- +-- Table: customers +-- +CREATE TABLE "customers" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "display_name" character varying(255) NOT NULL, + "full_name" character varying(255) NOT NULL, + "year_of_birth" integer NOT NULL, + "postcode" character varying(16) NOT NULL, + "latitude" numeric(5,2), + "longitude" numeric(5,2), + PRIMARY KEY ("id") +); +CREATE INDEX "customers_idx_entity_id" on "customers" ("entity_id"); + +; +-- +-- Table: entity_association +-- +CREATE TABLE "entity_association" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "lis" boolean, + "esta" boolean, + PRIMARY KEY ("id") +); +CREATE INDEX "entity_association_idx_entity_id" on "entity_association" ("entity_id"); + +; +-- +-- Table: gb_postcodes +-- +CREATE TABLE "gb_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) DEFAULT '' NOT NULL, + "latitude" numeric(7,5), + "longitude" numeric(7,5), + "ward_id" integer, + PRIMARY KEY ("outcode", "incode") +); +CREATE INDEX "gb_postcodes_idx_ward_id" on "gb_postcodes" ("ward_id"); + +; +-- +-- Table: global_medals +-- +CREATE TABLE "global_medals" ( + "id" serial NOT NULL, + "group_id" integer NOT NULL, + "threshold" integer NOT NULL, + "points" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_medals_idx_group_id" on "global_medals" ("group_id"); + +; +-- +-- Table: leaderboard_sets +-- +CREATE TABLE "leaderboard_sets" ( + "id" serial NOT NULL, + "leaderboard_id" integer NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "leaderboard_sets_idx_leaderboard_id" on "leaderboard_sets" ("leaderboard_id"); + +; +-- +-- Table: org_medals +-- +CREATE TABLE "org_medals" ( + "id" serial NOT NULL, + "group_id" integer NOT NULL, + "threshold" integer NOT NULL, + "points" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_medals_idx_group_id" on "org_medals" ("group_id"); + +; +-- +-- Table: transactions +-- +CREATE TABLE "transactions" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "proof_image" text, + "submitted_at" timestamp NOT NULL, + "purchase_time" timestamp NOT NULL, + "essential" boolean DEFAULT false NOT NULL, + "distance" numeric(15), + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_idx_buyer_id" on "transactions" ("buyer_id"); +CREATE INDEX "transactions_idx_seller_id" on "transactions" ("seller_id"); + +; +-- +-- Table: users +-- +CREATE TABLE "users" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "email" text NOT NULL, + "join_date" timestamp NOT NULL, + "password" character varying(100) NOT NULL, + "is_admin" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "users_email" UNIQUE ("email") +); +CREATE INDEX "users_idx_entity_id" on "users" ("entity_id"); + +; +-- +-- Table: device_tokens +-- +CREATE TABLE "device_tokens" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "token" character varying(200) NOT NULL, + "register_date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "device_tokens_idx_user_id" on "device_tokens" ("user_id"); + +; +-- +-- Table: feedback +-- +CREATE TABLE "feedback" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "feedbacktext" text NOT NULL, + "app_name" character varying(255) NOT NULL, + "package_name" character varying(255) NOT NULL, + "version_code" character varying(255) NOT NULL, + "version_number" character varying(255) NOT NULL, + "actioned" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "feedback_idx_user_id" on "feedback" ("user_id"); + +; +-- +-- Table: global_user_medal_progress +-- +CREATE TABLE "global_user_medal_progress" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "total" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_user_medal_progress_idx_entity_id" on "global_user_medal_progress" ("entity_id"); +CREATE INDEX "global_user_medal_progress_idx_group_id" on "global_user_medal_progress" ("group_id"); + +; +-- +-- Table: global_user_medals +-- +CREATE TABLE "global_user_medals" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "points" integer NOT NULL, + "awarded_at" timestamp NOT NULL, + "threshold" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_user_medals_idx_entity_id" on "global_user_medals" ("entity_id"); +CREATE INDEX "global_user_medals_idx_group_id" on "global_user_medals" ("group_id"); + +; +-- +-- Table: import_lookups +-- +CREATE TABLE "import_lookups" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_lookups_idx_entity_id" on "import_lookups" ("entity_id"); +CREATE INDEX "import_lookups_idx_set_id" on "import_lookups" ("set_id"); + +; +-- +-- Table: org_user_medal_progress +-- +CREATE TABLE "org_user_medal_progress" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "total" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_user_medal_progress_idx_entity_id" on "org_user_medal_progress" ("entity_id"); +CREATE INDEX "org_user_medal_progress_idx_group_id" on "org_user_medal_progress" ("group_id"); + +; +-- +-- Table: org_user_medals +-- +CREATE TABLE "org_user_medals" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "points" integer NOT NULL, + "awarded_at" timestamp NOT NULL, + "threshold" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_user_medals_idx_entity_id" on "org_user_medals" ("entity_id"); +CREATE INDEX "org_user_medals_idx_group_id" on "org_user_medals" ("group_id"); + +; +-- +-- Table: session_tokens +-- +CREATE TABLE "session_tokens" ( + "id" serial NOT NULL, + "token" character varying(255) NOT NULL, + "user_id" integer NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "session_tokens_token" UNIQUE ("token") +); +CREATE INDEX "session_tokens_idx_user_id" on "session_tokens" ("user_id"); + +; +-- +-- Table: transaction_recurring +-- +CREATE TABLE "transaction_recurring" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "start_time" timestamp NOT NULL, + "last_updated" timestamp, + "essential" boolean DEFAULT false NOT NULL, + "distance" numeric(15), + "category_id" integer, + "recurring_period" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transaction_recurring_idx_buyer_id" on "transaction_recurring" ("buyer_id"); +CREATE INDEX "transaction_recurring_idx_category_id" on "transaction_recurring" ("category_id"); +CREATE INDEX "transaction_recurring_idx_seller_id" on "transaction_recurring" ("seller_id"); + +; +-- +-- Table: transactions_meta +-- +CREATE TABLE "transactions_meta" ( + "id" serial NOT NULL, + "transaction_id" integer NOT NULL, + "net_value" numeric(100,0) NOT NULL, + "sales_tax_value" numeric(100,0) NOT NULL, + "gross_value" numeric(100,0) NOT NULL, + "local_service" boolean DEFAULT false NOT NULL, + "regional_service" boolean DEFAULT false NOT NULL, + "national_service" boolean DEFAULT false NOT NULL, + "private_household_rebate" boolean DEFAULT false NOT NULL, + "business_tax_and_rebate" boolean DEFAULT false NOT NULL, + "stat_loc_gov" boolean DEFAULT false NOT NULL, + "central_loc_gov" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_meta_idx_transaction_id" on "transactions_meta" ("transaction_id"); + +; +-- +-- Table: entities_postcodes +-- +CREATE TABLE "entities_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("outcode", "incode", "entity_id") +); +CREATE INDEX "entities_postcodes_idx_entity_id" on "entities_postcodes" ("entity_id"); +CREATE INDEX "entities_postcodes_idx_outcode_incode" on "entities_postcodes" ("outcode", "incode"); + +; +-- +-- Table: import_values +-- +CREATE TABLE "import_values" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "user_name" character varying(255) NOT NULL, + "purchase_date" timestamp NOT NULL, + "purchase_value" character varying(255) NOT NULL, + "org_name" character varying(255) NOT NULL, + "transaction_id" integer, + "ignore_value" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_values_idx_set_id" on "import_values" ("set_id"); +CREATE INDEX "import_values_idx_transaction_id" on "import_values" ("transaction_id"); + +; +-- +-- Table: leaderboard_values +-- +CREATE TABLE "leaderboard_values" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "set_id" integer NOT NULL, + "position" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "trend" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboard_values_entity_id_set_id" UNIQUE ("entity_id", "set_id") +); +CREATE INDEX "leaderboard_values_idx_entity_id" on "leaderboard_values" ("entity_id"); +CREATE INDEX "leaderboard_values_idx_set_id" on "leaderboard_values" ("set_id"); + +; +-- +-- Table: organisations +-- +CREATE TABLE "organisations" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "street_name" text, + "town" character varying(255) NOT NULL, + "postcode" character varying(16), + "country" character varying(255), + "sector" character varying(1), + "pending" boolean DEFAULT false NOT NULL, + "is_local" boolean, + "is_fair" boolean, + "submitted_by_id" integer, + "latitude" numeric(8,5), + "longitude" numeric(8,5), + "type_id" integer, + "social_type_id" integer, + "is_anchor" boolean DEFAULT FALSE NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisations_idx_entity_id" on "organisations" ("entity_id"); +CREATE INDEX "organisations_idx_type_id" on "organisations" ("type_id"); +CREATE INDEX "organisations_idx_social_type_id" on "organisations" ("social_type_id"); + +; +-- +-- Table: transaction_category +-- +CREATE TABLE "transaction_category" ( + "category_id" integer NOT NULL, + "transaction_id" integer NOT NULL, + CONSTRAINT "transaction_category_transaction_id" UNIQUE ("transaction_id") +); +CREATE INDEX "transaction_category_idx_category_id" on "transaction_category" ("category_id"); +CREATE INDEX "transaction_category_idx_transaction_id" on "transaction_category" ("transaction_id"); + +; +-- +-- Table: transactions_external +-- +CREATE TABLE "transactions_external" ( + "id" serial NOT NULL, + "transaction_id" integer NOT NULL, + "external_reference_id" integer NOT NULL, + "external_id" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "transactions_external_external_reference_id_external_id" UNIQUE ("external_reference_id", "external_id") +); +CREATE INDEX "transactions_external_idx_external_reference_id" on "transactions_external" ("external_reference_id"); +CREATE INDEX "transactions_external_idx_transaction_id" on "transactions_external" ("transaction_id"); + +; +-- +-- Table: organisation_payroll +-- +CREATE TABLE "organisation_payroll" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "entry_period" timestamp NOT NULL, + "employee_amount" integer NOT NULL, + "local_employee_amount" integer NOT NULL, + "gross_payroll" numeric(100,0) NOT NULL, + "payroll_income_tax" numeric(100,0) NOT NULL, + "payroll_employee_ni" numeric(100,0) NOT NULL, + "payroll_employer_ni" numeric(100,0) NOT NULL, + "payroll_total_pension" numeric(100,0) NOT NULL, + "payroll_other_benefit" numeric(100,0) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisation_payroll_idx_org_id" on "organisation_payroll" ("org_id"); + +; +-- +-- Table: organisations_external +-- +CREATE TABLE "organisations_external" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "external_reference_id" integer NOT NULL, + "external_id" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisations_external_external_reference_id_external_id" UNIQUE ("external_reference_id", "external_id") +); +CREATE INDEX "organisations_external_idx_external_reference_id" on "organisations_external" ("external_reference_id"); +CREATE INDEX "organisations_external_idx_org_id" on "organisations_external" ("org_id"); + +; +-- +-- Foreign Key Definitions +-- + +; +ALTER TABLE "customers" ADD CONSTRAINT "customers_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entity_association" ADD CONSTRAINT "entity_association_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "gb_postcodes" ADD CONSTRAINT "gb_postcodes_fk_ward_id" FOREIGN KEY ("ward_id") + REFERENCES "gb_wards" ("id") DEFERRABLE; + +; +ALTER TABLE "global_medals" ADD CONSTRAINT "global_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_sets" ADD CONSTRAINT "leaderboard_sets_fk_leaderboard_id" FOREIGN KEY ("leaderboard_id") + REFERENCES "leaderboards" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_medals" ADD CONSTRAINT "org_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "users" ADD CONSTRAINT "users_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "device_tokens" ADD CONSTRAINT "device_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "feedback" ADD CONSTRAINT "feedback_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "global_user_medal_progress" ADD CONSTRAINT "global_user_medal_progress_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "global_user_medal_progress" ADD CONSTRAINT "global_user_medal_progress_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "global_user_medals" ADD CONSTRAINT "global_user_medals_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "global_user_medals" ADD CONSTRAINT "global_user_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_user_medal_progress" ADD CONSTRAINT "org_user_medal_progress_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "org_user_medal_progress" ADD CONSTRAINT "org_user_medal_progress_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_user_medals" ADD CONSTRAINT "org_user_medals_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "org_user_medals" ADD CONSTRAINT "org_user_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "session_tokens" ADD CONSTRAINT "session_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") DEFERRABLE; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions_meta" ADD CONSTRAINT "transactions_meta_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entities_postcodes" ADD CONSTRAINT "entities_postcodes_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entities_postcodes" ADD CONSTRAINT "entities_postcodes_fk_outcode_incode" FOREIGN KEY ("outcode", "incode") + REFERENCES "gb_postcodes" ("outcode", "incode") DEFERRABLE; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "leaderboard_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_type_id" FOREIGN KEY ("type_id") + REFERENCES "organisation_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_social_type_id" FOREIGN KEY ("social_type_id") + REFERENCES "organisation_social_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions_external" ADD CONSTRAINT "transactions_external_fk_external_reference_id" FOREIGN KEY ("external_reference_id") + REFERENCES "external_references" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions_external" ADD CONSTRAINT "transactions_external_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisation_payroll" ADD CONSTRAINT "organisation_payroll_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") DEFERRABLE; + +; +ALTER TABLE "organisations_external" ADD CONSTRAINT "organisations_external_fk_external_reference_id" FOREIGN KEY ("external_reference_id") + REFERENCES "external_references" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations_external" ADD CONSTRAINT "organisations_external_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; diff --git a/share/ddl/PostgreSQL/upgrade/31-32/001-auto.sql b/share/ddl/PostgreSQL/upgrade/31-32/001-auto.sql new file mode 100644 index 0000000..5e0a369 --- /dev/null +++ b/share/ddl/PostgreSQL/upgrade/31-32/001-auto.sql @@ -0,0 +1,5 @@ +-- Convert schema 'share/ddl/_source/deploy/31/001-auto.yml' to 'share/ddl/_source/deploy/32/001-auto.yml':; + +; +-- No differences found; + diff --git a/share/ddl/SQLite/deploy/32/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/32/001-auto-__VERSION.sql new file mode 100644 index 0000000..0907ef1 --- /dev/null +++ b/share/ddl/SQLite/deploy/32/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Sat Nov 28 14:26:03 2020 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE dbix_class_deploymenthandler_versions ( + id INTEGER PRIMARY KEY NOT NULL, + version varchar(50) NOT NULL, + ddl text, + upgrade_sql text +); +CREATE UNIQUE INDEX dbix_class_deploymenthandler_versions_version ON dbix_class_deploymenthandler_versions (version); +COMMIT; diff --git a/share/ddl/SQLite/deploy/32/001-auto.sql b/share/ddl/SQLite/deploy/32/001-auto.sql new file mode 100644 index 0000000..c914bd8 --- /dev/null +++ b/share/ddl/SQLite/deploy/32/001-auto.sql @@ -0,0 +1,481 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Sat Nov 28 14:26:03 2020 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: account_tokens +-- +CREATE TABLE account_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + name text NOT NULL, + used integer NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX account_tokens_name ON account_tokens (name); +-- +-- Table: category +-- +CREATE TABLE category ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + line_icon varchar(255) +); +CREATE UNIQUE INDEX category_name ON category (name); +-- +-- Table: entities +-- +CREATE TABLE entities ( + id INTEGER PRIMARY KEY NOT NULL, + type varchar(255) NOT NULL +); +-- +-- Table: external_references +-- +CREATE TABLE external_references ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX external_references_name ON external_references (name); +-- +-- Table: gb_wards +-- +CREATE TABLE gb_wards ( + id INTEGER PRIMARY KEY NOT NULL, + ward varchar(100) NOT NULL +); +-- +-- Table: global_medal_group +-- +CREATE TABLE global_medal_group ( + id INTEGER PRIMARY KEY NOT NULL, + group_name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX global_medal_group_group_name ON global_medal_group (group_name); +-- +-- Table: import_sets +-- +CREATE TABLE import_sets ( + id INTEGER PRIMARY KEY NOT NULL, + date datetime NOT NULL +); +-- +-- Table: leaderboards +-- +CREATE TABLE leaderboards ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + type varchar(255) NOT NULL +); +CREATE UNIQUE INDEX leaderboards_type ON leaderboards (type); +-- +-- Table: org_medal_group +-- +CREATE TABLE org_medal_group ( + id INTEGER PRIMARY KEY NOT NULL, + group_name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX org_medal_group_group_name ON org_medal_group (group_name); +-- +-- Table: organisation_social_types +-- +CREATE TABLE organisation_social_types ( + id INTEGER PRIMARY KEY NOT NULL, + key varchar(255) NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX organisation_social_types_key ON organisation_social_types (key); +-- +-- Table: organisation_types +-- +CREATE TABLE organisation_types ( + id INTEGER PRIMARY KEY NOT NULL, + key varchar(255) NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX organisation_types_key ON organisation_types (key); +-- +-- Table: customers +-- +CREATE TABLE customers ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + display_name varchar(255) NOT NULL, + full_name varchar(255) NOT NULL, + year_of_birth integer NOT NULL, + postcode varchar(16) NOT NULL, + latitude decimal(5,2), + longitude decimal(5,2), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX customers_idx_entity_id ON customers (entity_id); +-- +-- Table: entity_association +-- +CREATE TABLE entity_association ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + lis boolean, + esta boolean, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX entity_association_idx_entity_id ON entity_association (entity_id); +-- +-- Table: gb_postcodes +-- +CREATE TABLE gb_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL DEFAULT '', + latitude decimal(7,5), + longitude decimal(7,5), + ward_id integer, + PRIMARY KEY (outcode, incode), + FOREIGN KEY (ward_id) REFERENCES gb_wards(id) +); +CREATE INDEX gb_postcodes_idx_ward_id ON gb_postcodes (ward_id); +-- +-- Table: global_medals +-- +CREATE TABLE global_medals ( + id INTEGER PRIMARY KEY NOT NULL, + group_id integer NOT NULL, + threshold integer NOT NULL, + points integer NOT NULL, + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_medals_idx_group_id ON global_medals (group_id); +-- +-- Table: leaderboard_sets +-- +CREATE TABLE leaderboard_sets ( + id INTEGER PRIMARY KEY NOT NULL, + leaderboard_id integer NOT NULL, + date datetime NOT NULL, + FOREIGN KEY (leaderboard_id) REFERENCES leaderboards(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_sets_idx_leaderboard_id ON leaderboard_sets (leaderboard_id); +-- +-- Table: org_medals +-- +CREATE TABLE org_medals ( + id INTEGER PRIMARY KEY NOT NULL, + group_id integer NOT NULL, + threshold integer NOT NULL, + points integer NOT NULL, + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_medals_idx_group_id ON org_medals (group_id); +-- +-- Table: transactions +-- +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + essential boolean NOT NULL DEFAULT false, + distance numeric(15), + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transactions_idx_buyer_id ON transactions (buyer_id); +CREATE INDEX transactions_idx_seller_id ON transactions (seller_id); +-- +-- Table: users +-- +CREATE TABLE users ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + email text NOT NULL, + join_date datetime NOT NULL, + password varchar(100) NOT NULL, + is_admin boolean NOT NULL DEFAULT false, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX users_idx_entity_id ON users (entity_id); +CREATE UNIQUE INDEX users_email ON users (email); +-- +-- Table: device_tokens +-- +CREATE TABLE device_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + token varchar(200) NOT NULL, + register_date datetime NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX device_tokens_idx_user_id ON device_tokens (user_id); +-- +-- Table: feedback +-- +CREATE TABLE feedback ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + submitted_at datetime NOT NULL, + feedbacktext text NOT NULL, + app_name varchar(255) NOT NULL, + package_name varchar(255) NOT NULL, + version_code varchar(255) NOT NULL, + version_number varchar(255) NOT NULL, + actioned boolean NOT NULL DEFAULT false, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX feedback_idx_user_id ON feedback (user_id); +-- +-- Table: global_user_medal_progress +-- +CREATE TABLE global_user_medal_progress ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + total integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_user_medal_progress_idx_entity_id ON global_user_medal_progress (entity_id); +CREATE INDEX global_user_medal_progress_idx_group_id ON global_user_medal_progress (group_id); +-- +-- Table: global_user_medals +-- +CREATE TABLE global_user_medals ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + points integer NOT NULL, + awarded_at datetime NOT NULL, + threshold integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_user_medals_idx_entity_id ON global_user_medals (entity_id); +CREATE INDEX global_user_medals_idx_group_id ON global_user_medals (group_id); +-- +-- Table: import_lookups +-- +CREATE TABLE import_lookups ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + name varchar(255) NOT NULL, + entity_id integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_lookups_idx_entity_id ON import_lookups (entity_id); +CREATE INDEX import_lookups_idx_set_id ON import_lookups (set_id); +-- +-- Table: org_user_medal_progress +-- +CREATE TABLE org_user_medal_progress ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + total integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_user_medal_progress_idx_entity_id ON org_user_medal_progress (entity_id); +CREATE INDEX org_user_medal_progress_idx_group_id ON org_user_medal_progress (group_id); +-- +-- Table: org_user_medals +-- +CREATE TABLE org_user_medals ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + points integer NOT NULL, + awarded_at datetime NOT NULL, + threshold integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_user_medals_idx_entity_id ON org_user_medals (entity_id); +CREATE INDEX org_user_medals_idx_group_id ON org_user_medals (group_id); +-- +-- Table: session_tokens +-- +CREATE TABLE session_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + token varchar(255) NOT NULL, + user_id integer NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX session_tokens_idx_user_id ON session_tokens (user_id); +CREATE UNIQUE INDEX session_tokens_token ON session_tokens (token); +-- +-- Table: transaction_recurring +-- +CREATE TABLE transaction_recurring ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + start_time datetime NOT NULL, + last_updated datetime, + essential boolean NOT NULL DEFAULT false, + distance numeric(15), + category_id integer, + recurring_period varchar(255) NOT NULL, + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (category_id) REFERENCES category(id), + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transaction_recurring_idx_buyer_id ON transaction_recurring (buyer_id); +CREATE INDEX transaction_recurring_idx_category_id ON transaction_recurring (category_id); +CREATE INDEX transaction_recurring_idx_seller_id ON transaction_recurring (seller_id); +-- +-- Table: transactions_meta +-- +CREATE TABLE transactions_meta ( + id INTEGER PRIMARY KEY NOT NULL, + transaction_id integer NOT NULL, + net_value numeric(100,0) NOT NULL, + sales_tax_value numeric(100,0) NOT NULL, + gross_value numeric(100,0) NOT NULL, + local_service boolean NOT NULL DEFAULT false, + regional_service boolean NOT NULL DEFAULT false, + national_service boolean NOT NULL DEFAULT false, + private_household_rebate boolean NOT NULL DEFAULT false, + business_tax_and_rebate boolean NOT NULL DEFAULT false, + stat_loc_gov boolean NOT NULL DEFAULT false, + central_loc_gov boolean NOT NULL DEFAULT false, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); +CREATE INDEX transactions_meta_idx_transaction_id ON transactions_meta (transaction_id); +-- +-- Table: entities_postcodes +-- +CREATE TABLE entities_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL, + entity_id integer NOT NULL, + PRIMARY KEY (outcode, incode, entity_id), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE, + FOREIGN KEY (outcode, incode) REFERENCES gb_postcodes(outcode, incode) +); +CREATE INDEX entities_postcodes_idx_entity_id ON entities_postcodes (entity_id); +CREATE INDEX entities_postcodes_idx_outcode_incode ON entities_postcodes (outcode, incode); +-- +-- Table: import_values +-- +CREATE TABLE import_values ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + user_name varchar(255) NOT NULL, + purchase_date datetime NOT NULL, + purchase_value varchar(255) NOT NULL, + org_name varchar(255) NOT NULL, + transaction_id integer, + ignore_value boolean NOT NULL DEFAULT false, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_values_idx_set_id ON import_values (set_id); +CREATE INDEX import_values_idx_transaction_id ON import_values (transaction_id); +-- +-- Table: leaderboard_values +-- +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_values_idx_entity_id ON leaderboard_values (entity_id); +CREATE INDEX leaderboard_values_idx_set_id ON leaderboard_values (set_id); +CREATE UNIQUE INDEX leaderboard_values_entity_id_set_id ON leaderboard_values (entity_id, set_id); +-- +-- Table: organisations +-- +CREATE TABLE organisations ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + name varchar(255) NOT NULL, + street_name text, + town varchar(255) NOT NULL, + postcode varchar(16), + country varchar(255), + sector varchar(1), + pending boolean NOT NULL DEFAULT false, + is_local boolean, + is_fair boolean, + submitted_by_id integer, + latitude decimal(8,5), + longitude decimal(8,5), + type_id integer, + social_type_id integer, + is_anchor boolean NOT NULL DEFAULT FALSE, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE, + FOREIGN KEY (type_id) REFERENCES organisation_types(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (social_type_id) REFERENCES organisation_social_types(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX organisations_idx_entity_id ON organisations (entity_id); +CREATE INDEX organisations_idx_type_id ON organisations (type_id); +CREATE INDEX organisations_idx_social_type_id ON organisations (social_type_id); +-- +-- Table: transaction_category +-- +CREATE TABLE transaction_category ( + category_id integer NOT NULL, + transaction_id integer NOT NULL, + FOREIGN KEY (category_id) REFERENCES category(id) ON DELETE CASCADE, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); +CREATE INDEX transaction_category_idx_category_id ON transaction_category (category_id); +CREATE INDEX transaction_category_idx_transaction_id ON transaction_category (transaction_id); +CREATE UNIQUE INDEX transaction_category_transaction_id ON transaction_category (transaction_id); +-- +-- Table: transactions_external +-- +CREATE TABLE transactions_external ( + id INTEGER PRIMARY KEY NOT NULL, + transaction_id integer NOT NULL, + external_reference_id integer NOT NULL, + external_id varchar(255) NOT NULL, + FOREIGN KEY (external_reference_id) REFERENCES external_references(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX transactions_external_idx_external_reference_id ON transactions_external (external_reference_id); +CREATE INDEX transactions_external_idx_transaction_id ON transactions_external (transaction_id); +CREATE UNIQUE INDEX transactions_external_external_reference_id_external_id ON transactions_external (external_reference_id, external_id); +-- +-- Table: organisation_payroll +-- +CREATE TABLE organisation_payroll ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + submitted_at datetime NOT NULL, + entry_period datetime NOT NULL, + employee_amount integer NOT NULL, + local_employee_amount integer NOT NULL, + gross_payroll numeric(100,0) NOT NULL, + payroll_income_tax numeric(100,0) NOT NULL, + payroll_employee_ni numeric(100,0) NOT NULL, + payroll_employer_ni numeric(100,0) NOT NULL, + payroll_total_pension numeric(100,0) NOT NULL, + payroll_other_benefit numeric(100,0) NOT NULL, + FOREIGN KEY (org_id) REFERENCES organisations(id) +); +CREATE INDEX organisation_payroll_idx_org_id ON organisation_payroll (org_id); +-- +-- Table: organisations_external +-- +CREATE TABLE organisations_external ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + external_reference_id integer NOT NULL, + external_id varchar(255) NOT NULL, + FOREIGN KEY (external_reference_id) REFERENCES external_references(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (org_id) REFERENCES organisations(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX organisations_external_idx_external_reference_id ON organisations_external (external_reference_id); +CREATE INDEX organisations_external_idx_org_id ON organisations_external (org_id); +CREATE UNIQUE INDEX organisations_external_external_reference_id_external_id ON organisations_external (external_reference_id, external_id); +COMMIT; diff --git a/share/ddl/SQLite/upgrade/31-32/001-auto.sql b/share/ddl/SQLite/upgrade/31-32/001-auto.sql new file mode 100644 index 0000000..5e0a369 --- /dev/null +++ b/share/ddl/SQLite/upgrade/31-32/001-auto.sql @@ -0,0 +1,5 @@ +-- Convert schema 'share/ddl/_source/deploy/31/001-auto.yml' to 'share/ddl/_source/deploy/32/001-auto.yml':; + +; +-- No differences found; + diff --git a/share/ddl/_source/deploy/32/001-auto-__VERSION.yml b/share/ddl/_source/deploy/32/001-auto-__VERSION.yml new file mode 100644 index 0000000..7f96b5c --- /dev/null +++ b/share/ddl/_source/deploy/32/001-auto-__VERSION.yml @@ -0,0 +1,91 @@ +--- +schema: + procedures: {} + tables: + dbix_class_deploymenthandler_versions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - version + match_type: '' + name: dbix_class_deploymenthandler_versions_version + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + ddl: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ddl + order: 3 + size: + - 0 + id: + data_type: int + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + upgrade_sql: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: upgrade_sql + order: 4 + size: + - 0 + version: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: version + order: 2 + size: + - 50 + indices: [] + name: dbix_class_deploymenthandler_versions + options: [] + order: 1 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - __VERSION + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 1.61 diff --git a/share/ddl/_source/deploy/32/001-auto.yml b/share/ddl/_source/deploy/32/001-auto.yml new file mode 100644 index 0000000..a7a79f1 --- /dev/null +++ b/share/ddl/_source/deploy/32/001-auto.yml @@ -0,0 +1,3629 @@ +--- +schema: + procedures: {} + tables: + account_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: account_tokens_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 0 + used: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: used + order: 3 + size: + - 0 + indices: [] + name: account_tokens + options: [] + order: 1 + category: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: category_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + line_icon: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: line_icon + order: 3 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 255 + indices: [] + name: category + options: [] + order: 2 + customers: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: customers_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + display_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: display_name + order: 3 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + full_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 4 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 7 + size: + - 5 + - 2 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 8 + size: + - 5 + - 2 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + year_of_birth: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: year_of_birth + order: 5 + size: + - 0 + indices: + - fields: + - entity_id + name: customers_idx_entity_id + options: [] + type: NORMAL + name: customers + options: [] + order: 12 + device_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: device_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + register_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: register_date + order: 4 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: token + order: 3 + size: + - 200 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + indices: + - fields: + - user_id + name: device_tokens_idx_user_id + options: [] + type: NORMAL + name: device_tokens + options: [] + order: 20 + entities: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: type + order: 2 + size: + - 255 + indices: [] + name: entities + options: [] + order: 3 + entities_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + - entity_id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entities_postcodes_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: entities_postcodes_fk_outcode_incode + on_delete: '' + on_update: '' + options: [] + reference_fields: + - outcode + - incode + reference_table: gb_postcodes + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: entity_id + order: 3 + size: + - 0 + incode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + indices: + - fields: + - entity_id + name: entities_postcodes_idx_entity_id + options: [] + type: NORMAL + - fields: + - outcode + - incode + name: entities_postcodes_idx_outcode_incode + options: [] + type: NORMAL + name: entities_postcodes + options: [] + order: 30 + entity_association: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entity_association_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + esta: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: esta + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + lis: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: lis + order: 3 + size: + - 0 + indices: + - fields: + - entity_id + name: entity_association_idx_entity_id + options: [] + type: NORMAL + name: entity_association + options: [] + order: 13 + external_references: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: external_references_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 255 + indices: [] + name: external_references + options: [] + order: 4 + feedback: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: feedback_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + actioned: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: actioned + order: 9 + size: + - 0 + app_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: app_name + order: 5 + size: + - 255 + feedbacktext: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: feedbacktext + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + package_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: package_name + order: 6 + size: + - 255 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + version_code: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_code + order: 7 + size: + - 255 + version_number: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_number + order: 8 + size: + - 255 + indices: + - fields: + - user_id + name: feedback_idx_user_id + options: [] + type: NORMAL + name: feedback + options: [] + order: 21 + gb_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - ward_id + match_type: '' + name: gb_postcodes_fk_ward_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: gb_wards + type: FOREIGN KEY + fields: + incode: + data_type: char + default_value: '' + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 3 + size: + - 7 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 4 + size: + - 7 + - 5 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + ward_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ward_id + order: 5 + size: + - 0 + indices: + - fields: + - ward_id + name: gb_postcodes_idx_ward_id + options: [] + type: NORMAL + name: gb_postcodes + options: [] + order: 14 + gb_wards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ward: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ward + order: 2 + size: + - 100 + indices: [] + name: gb_wards + options: [] + order: 5 + global_medal_group: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - group_name + match_type: '' + name: global_medal_group_group_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + group_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: group_name + order: 2 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: global_medal_group + options: [] + order: 6 + global_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 3 + size: + - 0 + indices: + - fields: + - group_id + name: global_medals_idx_group_id + options: [] + type: NORMAL + name: global_medals + options: [] + order: 15 + global_user_medal_progress: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: global_user_medal_progress_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_user_medal_progress_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + total: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: total + order: 4 + size: + - 0 + indices: + - fields: + - entity_id + name: global_user_medal_progress_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: global_user_medal_progress_idx_group_id + options: [] + type: NORMAL + name: global_user_medal_progress + options: [] + order: 22 + global_user_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: global_user_medals_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_user_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + awarded_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: awarded_at + order: 5 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 6 + size: + - 0 + indices: + - fields: + - entity_id + name: global_user_medals_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: global_user_medals_idx_group_id + options: [] + type: NORMAL + name: global_user_medals + options: [] + order: 23 + import_lookups: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: import_lookups_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_lookups_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + indices: + - fields: + - entity_id + name: import_lookups_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: import_lookups_idx_set_id + options: [] + type: NORMAL + name: import_lookups + options: [] + order: 24 + import_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: import_sets + options: [] + order: 7 + import_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: import_values_fk_transaction_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ignore_value: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ignore_value + order: 8 + size: + - 0 + org_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_name + order: 6 + size: + - 255 + purchase_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_date + order: 4 + size: + - 0 + purchase_value: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_value + order: 5 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 7 + size: + - 0 + user_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_name + order: 3 + size: + - 255 + indices: + - fields: + - set_id + name: import_values_idx_set_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: import_values_idx_transaction_id + options: [] + type: NORMAL + name: import_values + options: [] + order: 31 + leaderboard_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - leaderboard_id + match_type: '' + name: leaderboard_sets_fk_leaderboard_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboards + type: FOREIGN KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + leaderboard_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: leaderboard_id + order: 2 + size: + - 0 + indices: + - fields: + - leaderboard_id + name: leaderboard_sets_idx_leaderboard_id + options: [] + type: NORMAL + name: leaderboard_sets + options: [] + order: 16 + leaderboard_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + - set_id + match_type: '' + name: leaderboard_values_entity_id_set_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - entity_id + match_type: '' + name: leaderboard_values_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: leaderboard_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboard_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + position: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: position + order: 4 + size: + - 0 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: set_id + order: 3 + size: + - 0 + trend: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: trend + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 5 + size: + - 100 + - 0 + indices: + - fields: + - entity_id + name: leaderboard_values_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: leaderboard_values_idx_set_id + options: [] + type: NORMAL + name: leaderboard_values + options: [] + order: 32 + leaderboards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - type + match_type: '' + name: leaderboards_type + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 255 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: type + order: 3 + size: + - 255 + indices: [] + name: leaderboards + options: [] + order: 8 + org_medal_group: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - group_name + match_type: '' + name: org_medal_group_group_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + group_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: group_name + order: 2 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: org_medal_group + options: [] + order: 9 + org_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 3 + size: + - 0 + indices: + - fields: + - group_id + name: org_medals_idx_group_id + options: [] + type: NORMAL + name: org_medals + options: [] + order: 17 + org_user_medal_progress: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: org_user_medal_progress_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_user_medal_progress_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + total: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: total + order: 4 + size: + - 0 + indices: + - fields: + - entity_id + name: org_user_medal_progress_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: org_user_medal_progress_idx_group_id + options: [] + type: NORMAL + name: org_user_medal_progress + options: [] + order: 25 + org_user_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: org_user_medals_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_user_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + awarded_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: awarded_at + order: 5 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 6 + size: + - 0 + indices: + - fields: + - entity_id + name: org_user_medals_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: org_user_medals_idx_group_id + options: [] + type: NORMAL + name: org_user_medals + options: [] + order: 26 + organisation_payroll: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisation_payroll_fk_org_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: employee_amount + order: 5 + size: + - 0 + entry_period: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entry_period + order: 4 + size: + - 0 + gross_payroll: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_payroll + order: 7 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_employee_amount + order: 6 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + payroll_employee_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employee_ni + order: 9 + size: + - 100 + - 0 + payroll_employer_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employer_ni + order: 10 + size: + - 100 + - 0 + payroll_income_tax: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_income_tax + order: 8 + size: + - 100 + - 0 + payroll_other_benefit: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_other_benefit + order: 12 + size: + - 100 + - 0 + payroll_total_pension: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_total_pension + order: 11 + size: + - 100 + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + indices: + - fields: + - org_id + name: organisation_payroll_idx_org_id + options: [] + type: NORMAL + name: organisation_payroll + options: [] + order: 36 + organisation_social_types: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - key + match_type: '' + name: organisation_social_types_key + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + key: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: key + order: 2 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + indices: [] + name: organisation_social_types + options: [] + order: 10 + organisation_types: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - key + match_type: '' + name: organisation_types_key + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + key: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: key + order: 2 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + indices: [] + name: organisation_types + options: [] + order: 11 + organisations: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: organisations_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - type_id + match_type: '' + name: organisations_fk_type_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisation_types + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - social_type_id + match_type: '' + name: organisations_fk_social_type_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisation_social_types + type: FOREIGN KEY + fields: + country: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: country + order: 7 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_anchor: + data_type: boolean + default_value: !!perl/ref + =: FALSE + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_anchor + order: 17 + size: + - 0 + is_fair: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_fair + order: 11 + size: + - 0 + is_local: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_local + order: 10 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 13 + size: + - 8 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 14 + size: + - 8 + - 5 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + pending: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: pending + order: 9 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + sector: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: sector + order: 8 + size: + - 1 + social_type_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: social_type_id + order: 16 + size: + - 0 + street_name: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: street_name + order: 4 + size: + - 0 + submitted_by_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: submitted_by_id + order: 12 + size: + - 0 + town: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: town + order: 5 + size: + - 255 + type_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: type_id + order: 15 + size: + - 0 + indices: + - fields: + - entity_id + name: organisations_idx_entity_id + options: [] + type: NORMAL + - fields: + - type_id + name: organisations_idx_type_id + options: [] + type: NORMAL + - fields: + - social_type_id + name: organisations_idx_social_type_id + options: [] + type: NORMAL + name: organisations + options: [] + order: 33 + organisations_external: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - external_reference_id + - external_id + match_type: '' + name: organisations_external_external_reference_id_external_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - external_reference_id + match_type: '' + name: organisations_external_fk_external_reference_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: external_references + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisations_external_fk_org_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + external_id: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_id + order: 4 + size: + - 255 + external_reference_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_reference_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + indices: + - fields: + - external_reference_id + name: organisations_external_idx_external_reference_id + options: [] + type: NORMAL + - fields: + - org_id + name: organisations_external_idx_org_id + options: [] + type: NORMAL + name: organisations_external + options: [] + order: 37 + session_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - token + match_type: '' + name: session_tokens_token + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: session_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: token + order: 2 + size: + - 255 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 3 + size: + - 0 + indices: + - fields: + - user_id + name: session_tokens_idx_user_id + options: [] + type: NORMAL + name: session_tokens + options: [] + order: 27 + transaction_category: + constraints: + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_transaction_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - category_id + match_type: '' + name: transaction_category_fk_category_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: category + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_fk_transaction_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + category_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: category_id + order: 1 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - category_id + name: transaction_category_idx_category_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: transaction_category_idx_transaction_id + options: [] + type: NORMAL + name: transaction_category + options: [] + order: 34 + transaction_recurring: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transaction_recurring_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - category_id + match_type: '' + name: transaction_recurring_fk_category_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: category + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transaction_recurring_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + category_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: category_id + order: 9 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 8 + size: + - 15 + essential: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: essential + order: 7 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + last_updated: + data_type: datetime + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: last_updated + order: 6 + size: + - 0 + recurring_period: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: recurring_period + order: 10 + size: + - 255 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + start_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: start_time + order: 5 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transaction_recurring_idx_buyer_id + options: [] + type: NORMAL + - fields: + - category_id + name: transaction_recurring_idx_category_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transaction_recurring_idx_seller_id + options: [] + type: NORMAL + name: transaction_recurring + options: [] + order: 28 + transactions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transactions_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transactions_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 9 + size: + - 15 + essential: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: essential + order: 8 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + proof_image: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: proof_image + order: 5 + size: + - 0 + purchase_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_time + order: 7 + size: + - 0 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transactions_idx_buyer_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transactions_idx_seller_id + options: [] + type: NORMAL + name: transactions + options: [] + order: 18 + transactions_external: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - external_reference_id + - external_id + match_type: '' + name: transactions_external_external_reference_id_external_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - external_reference_id + match_type: '' + name: transactions_external_fk_external_reference_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: external_references + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transactions_external_fk_transaction_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + external_id: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_id + order: 4 + size: + - 255 + external_reference_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_reference_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - external_reference_id + name: transactions_external_idx_external_reference_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: transactions_external_idx_transaction_id + options: [] + type: NORMAL + name: transactions_external + options: [] + order: 35 + transactions_meta: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transactions_meta_fk_transaction_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + business_tax_and_rebate: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: business_tax_and_rebate + order: 10 + size: + - 0 + central_loc_gov: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: central_loc_gov + order: 12 + size: + - 0 + gross_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_value + order: 5 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_service + order: 6 + size: + - 0 + national_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: national_service + order: 8 + size: + - 0 + net_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: net_value + order: 3 + size: + - 100 + - 0 + private_household_rebate: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: private_household_rebate + order: 9 + size: + - 0 + regional_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: regional_service + order: 7 + size: + - 0 + sales_tax_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: sales_tax_value + order: 4 + size: + - 100 + - 0 + stat_loc_gov: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: stat_loc_gov + order: 11 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - transaction_id + name: transactions_meta_idx_transaction_id + options: [] + type: NORMAL + name: transactions_meta + options: [] + order: 29 + users: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: users_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: users_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 3 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_admin: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_admin + order: 6 + size: + - 0 + join_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: join_date + order: 4 + size: + - 0 + password: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: password + order: 5 + size: + - 100 + indices: + - fields: + - entity_id + name: users_idx_entity_id + options: [] + type: NORMAL + name: users + options: [] + order: 19 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - AccountToken + - Category + - Customer + - DeviceToken + - Entity + - EntityAssociation + - EntityPostcode + - ExternalReference + - Feedback + - GbPostcode + - GbWard + - GlobalMedalGroup + - GlobalMedals + - GlobalUserMedalProgress + - GlobalUserMedals + - ImportLookup + - ImportSet + - ImportValue + - Leaderboard + - LeaderboardSet + - LeaderboardValue + - OrgMedalGroup + - OrgMedals + - OrgUserMedalProgress + - OrgUserMedals + - Organisation + - OrganisationExternal + - OrganisationPayroll + - OrganisationSocialType + - OrganisationType + - SessionToken + - Transaction + - TransactionCategory + - TransactionExternal + - TransactionMeta + - TransactionRecurring + - User + - ViewQuantisedTransactionCategoryPg + - ViewQuantisedTransactionCategorySQLite + - ViewQuantisedTransactionPg + - ViewQuantisedTransactionSQLite + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 1.61 From bb161dfd25e944d6b80324fd7bc9d5304b62ff7d Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Mon, 30 Nov 2020 17:34:13 +0000 Subject: [PATCH 260/289] Add push notifications and device token management --- lib/Pear/LocalLoop.pm | 2 + .../LocalLoop/Controller/Api/Sendmessage.pm | 33 +- lib/Pear/LocalLoop/Schema.pm | 2 +- .../Schema/Result/DeviceSubscription.pm | 44 + .../LocalLoop/Schema/Result/DeviceToken.pm | 9 + lib/Pear/LocalLoop/Schema/Result/Topic.pm | 40 + .../deploy/33/001-auto-__VERSION.sql | 18 + share/ddl/PostgreSQL/deploy/33/001-auto.sql | 748 ++++ .../ddl/PostgreSQL/upgrade/32-33/001-auto.sql | 34 + .../SQLite/deploy/33/001-auto-__VERSION.sql | 18 + share/ddl/SQLite/deploy/33/001-auto.sql | 500 +++ share/ddl/SQLite/upgrade/32-33/001-auto.sql | 30 + .../_source/deploy/33/001-auto-__VERSION.yml | 91 + share/ddl/_source/deploy/33/001-auto.yml | 3757 +++++++++++++++++ 14 files changed, 5320 insertions(+), 6 deletions(-) create mode 100644 lib/Pear/LocalLoop/Schema/Result/DeviceSubscription.pm create mode 100644 lib/Pear/LocalLoop/Schema/Result/Topic.pm create mode 100644 share/ddl/PostgreSQL/deploy/33/001-auto-__VERSION.sql create mode 100644 share/ddl/PostgreSQL/deploy/33/001-auto.sql create mode 100644 share/ddl/PostgreSQL/upgrade/32-33/001-auto.sql create mode 100644 share/ddl/SQLite/deploy/33/001-auto-__VERSION.sql create mode 100644 share/ddl/SQLite/deploy/33/001-auto.sql create mode 100644 share/ddl/SQLite/upgrade/32-33/001-auto.sql create mode 100644 share/ddl/_source/deploy/33/001-auto-__VERSION.yml create mode 100644 share/ddl/_source/deploy/33/001-auto.yml diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 51ccba5..20dae07 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -142,7 +142,9 @@ sub startup { $api_public->post('/register')->to('api-register#post_register'); $api_public->post('/logout')->to('api-auth#post_logout'); $api_public->post('/feedback')->to('api-feedback#post_feedback'); + $api_public->post('/check-device-token')->to('api-devices#check_token'); $api_public->post('/add-device-token')->to('api-devices#add_token'); + $api_public->post('/get-topics')->to('api-sendmessage#get_topics'); $api_public->post('/get-device-tokens')->to('api-devices#get_tokens'); $api_public->post('/send-message')->to('api-sendmessage#post_message'); diff --git a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm index a758047..e518b78 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm @@ -9,9 +9,12 @@ use Carp; has error_messages => sub { return { - devicetoken => { - required => { message => 'Device token is required', status => 400 }, - in_resultset => { message => 'Device token not found', status => 400 }, + #devicetokens => { + # required => { message => 'Device token is required', status => 400 }, + # in_resultset => { message => 'Device token not found', status => 400 }, + #}, + topic => { + required => { message => 'Topic is required', status => 400 }, }, sender => { required => { message => 'Sender name is required', status => 400 }, @@ -66,13 +69,33 @@ sub create_jwt_from_path_and_scopes return $jwt->encode; } +sub get_topics { + my $c = shift; + + my $topic_rs = $c->schema->resultset('Topic'); + + my @topics = ( + map {{ + id => $_->id, + name => $_->name, + numberOfSubscribers => $_->search_related('device_subscriptions', {'topic_id' => $_->id})->count, + }} $topic_rs->all + ); + + return $c->render( json => { + success => Mojo::JSON->true, + topics => \@topics, + }); +} + sub post_message { my $c = shift; my $validation = $c->validation; $validation->input( $c->stash->{api_json} ); - $validation->required('devicetoken')->in_resultset('token', $c->schema->resultset('DeviceToken')); + #$validation->required('devicetokens')->in_resultset('token', $c->schema->resultset('DeviceToken')); + $validation->required('topic'); $validation->required('sender')->in_resultset('name', $c->schema->resultset('Organisation')); $validation->required('messagetext'); @@ -86,7 +109,7 @@ sub post_message { $request->content(JSON::encode_json ({ message => { - token => $validation->param('devicetoken'), + topic => $validation->param('topic'), notification => { title => $validation->param('sender'), body => $validation->param('messagetext') diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index 59fec01..0637931 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -6,7 +6,7 @@ use warnings; use base 'DBIx::Class::Schema'; -our $VERSION = 32; +our $VERSION = 33; __PACKAGE__->load_namespaces; diff --git a/lib/Pear/LocalLoop/Schema/Result/DeviceSubscription.pm b/lib/Pear/LocalLoop/Schema/Result/DeviceSubscription.pm new file mode 100644 index 0000000..0ef62ad --- /dev/null +++ b/lib/Pear/LocalLoop/Schema/Result/DeviceSubscription.pm @@ -0,0 +1,44 @@ +package Pear::LocalLoop::Schema::Result::DeviceSubscription; + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +__PACKAGE__->table("device_subscriptions"); + +__PACKAGE__->add_columns( + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "device_token_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "topic_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, +); + +__PACKAGE__->set_primary_key("id"); + +__PACKAGE__->belongs_to( + "device_token", + "Pear::LocalLoop::Schema::Result::DeviceToken", + "device_token_id", + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, +); + +__PACKAGE__->belongs_to( + "topic", + "Pear::LocalLoop::Schema::Result::Topic", + "topic_id", + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, +); + +1; diff --git a/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm b/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm index 3fd4686..ebb7fe7 100644 --- a/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm +++ b/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm @@ -44,4 +44,13 @@ __PACKAGE__->belongs_to( { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); +__PACKAGE__->has_many( + "device_subscriptions", + "Pear::LocalLoop::Schema::Result::DeviceSubscription", + { "foreign.device_token_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + +__PACKAGE__->many_to_many('topics' => 'device_subscriptions', 'topic'); + 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Topic.pm b/lib/Pear/LocalLoop/Schema/Result/Topic.pm new file mode 100644 index 0000000..cae97bd --- /dev/null +++ b/lib/Pear/LocalLoop/Schema/Result/Topic.pm @@ -0,0 +1,40 @@ +package Pear::LocalLoop::Schema::Result::Topic; + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +__PACKAGE__->load_components( qw/ + InflateColumn::DateTime + TimeStamp + FilterColumn +/); + +__PACKAGE__->table("topics"); + +__PACKAGE__->add_columns( + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "name" => { + data_type => "varchar", + size => 200, + is_nullable => 0, + }, +); + +__PACKAGE__->set_primary_key("id"); + +__PACKAGE__->has_many( + "device_subscriptions", + "Pear::LocalLoop::Schema::Result::DeviceSubscription", + { "foreign.topic_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + +__PACKAGE__->many_to_many('device_tokens' => 'device_subscriptions', 'device_token'); + +1; diff --git a/share/ddl/PostgreSQL/deploy/33/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/33/001-auto-__VERSION.sql new file mode 100644 index 0000000..c4582c2 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/33/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Mon Nov 30 14:29:37 2020 +-- +; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE "dbix_class_deploymenthandler_versions" ( + "id" serial NOT NULL, + "version" character varying(50) NOT NULL, + "ddl" text, + "upgrade_sql" text, + PRIMARY KEY ("id"), + CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version") +); + +; diff --git a/share/ddl/PostgreSQL/deploy/33/001-auto.sql b/share/ddl/PostgreSQL/deploy/33/001-auto.sql new file mode 100644 index 0000000..a87ce8e --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/33/001-auto.sql @@ -0,0 +1,748 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Mon Nov 30 14:29:36 2020 +-- +; +-- +-- Table: account_tokens +-- +CREATE TABLE "account_tokens" ( + "id" serial NOT NULL, + "name" text NOT NULL, + "used" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "account_tokens_name" UNIQUE ("name") +); + +; +-- +-- Table: category +-- +CREATE TABLE "category" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "line_icon" character varying(255), + PRIMARY KEY ("id"), + CONSTRAINT "category_name" UNIQUE ("name") +); + +; +-- +-- Table: entities +-- +CREATE TABLE "entities" ( + "id" serial NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: external_references +-- +CREATE TABLE "external_references" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "external_references_name" UNIQUE ("name") +); + +; +-- +-- Table: gb_wards +-- +CREATE TABLE "gb_wards" ( + "id" serial NOT NULL, + "ward" character varying(100) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: global_medal_group +-- +CREATE TABLE "global_medal_group" ( + "id" serial NOT NULL, + "group_name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "global_medal_group_group_name" UNIQUE ("group_name") +); + +; +-- +-- Table: import_sets +-- +CREATE TABLE "import_sets" ( + "id" serial NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: leaderboards +-- +CREATE TABLE "leaderboards" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboards_type" UNIQUE ("type") +); + +; +-- +-- Table: org_medal_group +-- +CREATE TABLE "org_medal_group" ( + "id" serial NOT NULL, + "group_name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "org_medal_group_group_name" UNIQUE ("group_name") +); + +; +-- +-- Table: organisation_social_types +-- +CREATE TABLE "organisation_social_types" ( + "id" serial NOT NULL, + "key" character varying(255) NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisation_social_types_key" UNIQUE ("key") +); + +; +-- +-- Table: organisation_types +-- +CREATE TABLE "organisation_types" ( + "id" serial NOT NULL, + "key" character varying(255) NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisation_types_key" UNIQUE ("key") +); + +; +-- +-- Table: topics +-- +CREATE TABLE "topics" ( + "id" serial NOT NULL, + "name" character varying(200) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: customers +-- +CREATE TABLE "customers" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "display_name" character varying(255) NOT NULL, + "full_name" character varying(255) NOT NULL, + "year_of_birth" integer NOT NULL, + "postcode" character varying(16) NOT NULL, + "latitude" numeric(5,2), + "longitude" numeric(5,2), + PRIMARY KEY ("id") +); +CREATE INDEX "customers_idx_entity_id" on "customers" ("entity_id"); + +; +-- +-- Table: entity_association +-- +CREATE TABLE "entity_association" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "lis" boolean, + "esta" boolean, + PRIMARY KEY ("id") +); +CREATE INDEX "entity_association_idx_entity_id" on "entity_association" ("entity_id"); + +; +-- +-- Table: gb_postcodes +-- +CREATE TABLE "gb_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) DEFAULT '' NOT NULL, + "latitude" numeric(7,5), + "longitude" numeric(7,5), + "ward_id" integer, + PRIMARY KEY ("outcode", "incode") +); +CREATE INDEX "gb_postcodes_idx_ward_id" on "gb_postcodes" ("ward_id"); + +; +-- +-- Table: global_medals +-- +CREATE TABLE "global_medals" ( + "id" serial NOT NULL, + "group_id" integer NOT NULL, + "threshold" integer NOT NULL, + "points" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_medals_idx_group_id" on "global_medals" ("group_id"); + +; +-- +-- Table: leaderboard_sets +-- +CREATE TABLE "leaderboard_sets" ( + "id" serial NOT NULL, + "leaderboard_id" integer NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "leaderboard_sets_idx_leaderboard_id" on "leaderboard_sets" ("leaderboard_id"); + +; +-- +-- Table: org_medals +-- +CREATE TABLE "org_medals" ( + "id" serial NOT NULL, + "group_id" integer NOT NULL, + "threshold" integer NOT NULL, + "points" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_medals_idx_group_id" on "org_medals" ("group_id"); + +; +-- +-- Table: transactions +-- +CREATE TABLE "transactions" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "proof_image" text, + "submitted_at" timestamp NOT NULL, + "purchase_time" timestamp NOT NULL, + "essential" boolean DEFAULT false NOT NULL, + "distance" numeric(15), + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_idx_buyer_id" on "transactions" ("buyer_id"); +CREATE INDEX "transactions_idx_seller_id" on "transactions" ("seller_id"); + +; +-- +-- Table: users +-- +CREATE TABLE "users" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "email" text NOT NULL, + "join_date" timestamp NOT NULL, + "password" character varying(100) NOT NULL, + "is_admin" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "users_email" UNIQUE ("email") +); +CREATE INDEX "users_idx_entity_id" on "users" ("entity_id"); + +; +-- +-- Table: device_tokens +-- +CREATE TABLE "device_tokens" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "token" character varying(200) NOT NULL, + "register_date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "device_tokens_idx_user_id" on "device_tokens" ("user_id"); + +; +-- +-- Table: feedback +-- +CREATE TABLE "feedback" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "feedbacktext" text NOT NULL, + "app_name" character varying(255) NOT NULL, + "package_name" character varying(255) NOT NULL, + "version_code" character varying(255) NOT NULL, + "version_number" character varying(255) NOT NULL, + "actioned" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "feedback_idx_user_id" on "feedback" ("user_id"); + +; +-- +-- Table: global_user_medal_progress +-- +CREATE TABLE "global_user_medal_progress" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "total" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_user_medal_progress_idx_entity_id" on "global_user_medal_progress" ("entity_id"); +CREATE INDEX "global_user_medal_progress_idx_group_id" on "global_user_medal_progress" ("group_id"); + +; +-- +-- Table: global_user_medals +-- +CREATE TABLE "global_user_medals" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "points" integer NOT NULL, + "awarded_at" timestamp NOT NULL, + "threshold" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_user_medals_idx_entity_id" on "global_user_medals" ("entity_id"); +CREATE INDEX "global_user_medals_idx_group_id" on "global_user_medals" ("group_id"); + +; +-- +-- Table: import_lookups +-- +CREATE TABLE "import_lookups" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_lookups_idx_entity_id" on "import_lookups" ("entity_id"); +CREATE INDEX "import_lookups_idx_set_id" on "import_lookups" ("set_id"); + +; +-- +-- Table: org_user_medal_progress +-- +CREATE TABLE "org_user_medal_progress" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "total" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_user_medal_progress_idx_entity_id" on "org_user_medal_progress" ("entity_id"); +CREATE INDEX "org_user_medal_progress_idx_group_id" on "org_user_medal_progress" ("group_id"); + +; +-- +-- Table: org_user_medals +-- +CREATE TABLE "org_user_medals" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "points" integer NOT NULL, + "awarded_at" timestamp NOT NULL, + "threshold" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_user_medals_idx_entity_id" on "org_user_medals" ("entity_id"); +CREATE INDEX "org_user_medals_idx_group_id" on "org_user_medals" ("group_id"); + +; +-- +-- Table: session_tokens +-- +CREATE TABLE "session_tokens" ( + "id" serial NOT NULL, + "token" character varying(255) NOT NULL, + "user_id" integer NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "session_tokens_token" UNIQUE ("token") +); +CREATE INDEX "session_tokens_idx_user_id" on "session_tokens" ("user_id"); + +; +-- +-- Table: transaction_recurring +-- +CREATE TABLE "transaction_recurring" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "start_time" timestamp NOT NULL, + "last_updated" timestamp, + "essential" boolean DEFAULT false NOT NULL, + "distance" numeric(15), + "category_id" integer, + "recurring_period" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transaction_recurring_idx_buyer_id" on "transaction_recurring" ("buyer_id"); +CREATE INDEX "transaction_recurring_idx_category_id" on "transaction_recurring" ("category_id"); +CREATE INDEX "transaction_recurring_idx_seller_id" on "transaction_recurring" ("seller_id"); + +; +-- +-- Table: transactions_meta +-- +CREATE TABLE "transactions_meta" ( + "id" serial NOT NULL, + "transaction_id" integer NOT NULL, + "net_value" numeric(100,0) NOT NULL, + "sales_tax_value" numeric(100,0) NOT NULL, + "gross_value" numeric(100,0) NOT NULL, + "local_service" boolean DEFAULT false NOT NULL, + "regional_service" boolean DEFAULT false NOT NULL, + "national_service" boolean DEFAULT false NOT NULL, + "private_household_rebate" boolean DEFAULT false NOT NULL, + "business_tax_and_rebate" boolean DEFAULT false NOT NULL, + "stat_loc_gov" boolean DEFAULT false NOT NULL, + "central_loc_gov" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_meta_idx_transaction_id" on "transactions_meta" ("transaction_id"); + +; +-- +-- Table: entities_postcodes +-- +CREATE TABLE "entities_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("outcode", "incode", "entity_id") +); +CREATE INDEX "entities_postcodes_idx_entity_id" on "entities_postcodes" ("entity_id"); +CREATE INDEX "entities_postcodes_idx_outcode_incode" on "entities_postcodes" ("outcode", "incode"); + +; +-- +-- Table: import_values +-- +CREATE TABLE "import_values" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "user_name" character varying(255) NOT NULL, + "purchase_date" timestamp NOT NULL, + "purchase_value" character varying(255) NOT NULL, + "org_name" character varying(255) NOT NULL, + "transaction_id" integer, + "ignore_value" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_values_idx_set_id" on "import_values" ("set_id"); +CREATE INDEX "import_values_idx_transaction_id" on "import_values" ("transaction_id"); + +; +-- +-- Table: leaderboard_values +-- +CREATE TABLE "leaderboard_values" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "set_id" integer NOT NULL, + "position" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "trend" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboard_values_entity_id_set_id" UNIQUE ("entity_id", "set_id") +); +CREATE INDEX "leaderboard_values_idx_entity_id" on "leaderboard_values" ("entity_id"); +CREATE INDEX "leaderboard_values_idx_set_id" on "leaderboard_values" ("set_id"); + +; +-- +-- Table: organisations +-- +CREATE TABLE "organisations" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "street_name" text, + "town" character varying(255) NOT NULL, + "postcode" character varying(16), + "country" character varying(255), + "sector" character varying(1), + "pending" boolean DEFAULT false NOT NULL, + "is_local" boolean, + "is_fair" boolean, + "submitted_by_id" integer, + "latitude" numeric(8,5), + "longitude" numeric(8,5), + "type_id" integer, + "social_type_id" integer, + "is_anchor" boolean DEFAULT FALSE NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisations_idx_entity_id" on "organisations" ("entity_id"); +CREATE INDEX "organisations_idx_type_id" on "organisations" ("type_id"); +CREATE INDEX "organisations_idx_social_type_id" on "organisations" ("social_type_id"); + +; +-- +-- Table: transaction_category +-- +CREATE TABLE "transaction_category" ( + "category_id" integer NOT NULL, + "transaction_id" integer NOT NULL, + CONSTRAINT "transaction_category_transaction_id" UNIQUE ("transaction_id") +); +CREATE INDEX "transaction_category_idx_category_id" on "transaction_category" ("category_id"); +CREATE INDEX "transaction_category_idx_transaction_id" on "transaction_category" ("transaction_id"); + +; +-- +-- Table: transactions_external +-- +CREATE TABLE "transactions_external" ( + "id" serial NOT NULL, + "transaction_id" integer NOT NULL, + "external_reference_id" integer NOT NULL, + "external_id" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "transactions_external_external_reference_id_external_id" UNIQUE ("external_reference_id", "external_id") +); +CREATE INDEX "transactions_external_idx_external_reference_id" on "transactions_external" ("external_reference_id"); +CREATE INDEX "transactions_external_idx_transaction_id" on "transactions_external" ("transaction_id"); + +; +-- +-- Table: device_subscriptions +-- +CREATE TABLE "device_subscriptions" ( + "id" serial NOT NULL, + "device_token_id" integer NOT NULL, + "topic_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "device_subscriptions_idx_device_token_id" on "device_subscriptions" ("device_token_id"); +CREATE INDEX "device_subscriptions_idx_topic_id" on "device_subscriptions" ("topic_id"); + +; +-- +-- Table: organisation_payroll +-- +CREATE TABLE "organisation_payroll" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "entry_period" timestamp NOT NULL, + "employee_amount" integer NOT NULL, + "local_employee_amount" integer NOT NULL, + "gross_payroll" numeric(100,0) NOT NULL, + "payroll_income_tax" numeric(100,0) NOT NULL, + "payroll_employee_ni" numeric(100,0) NOT NULL, + "payroll_employer_ni" numeric(100,0) NOT NULL, + "payroll_total_pension" numeric(100,0) NOT NULL, + "payroll_other_benefit" numeric(100,0) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisation_payroll_idx_org_id" on "organisation_payroll" ("org_id"); + +; +-- +-- Table: organisations_external +-- +CREATE TABLE "organisations_external" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "external_reference_id" integer NOT NULL, + "external_id" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisations_external_external_reference_id_external_id" UNIQUE ("external_reference_id", "external_id") +); +CREATE INDEX "organisations_external_idx_external_reference_id" on "organisations_external" ("external_reference_id"); +CREATE INDEX "organisations_external_idx_org_id" on "organisations_external" ("org_id"); + +; +-- +-- Foreign Key Definitions +-- + +; +ALTER TABLE "customers" ADD CONSTRAINT "customers_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entity_association" ADD CONSTRAINT "entity_association_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "gb_postcodes" ADD CONSTRAINT "gb_postcodes_fk_ward_id" FOREIGN KEY ("ward_id") + REFERENCES "gb_wards" ("id") DEFERRABLE; + +; +ALTER TABLE "global_medals" ADD CONSTRAINT "global_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_sets" ADD CONSTRAINT "leaderboard_sets_fk_leaderboard_id" FOREIGN KEY ("leaderboard_id") + REFERENCES "leaderboards" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_medals" ADD CONSTRAINT "org_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "users" ADD CONSTRAINT "users_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "device_tokens" ADD CONSTRAINT "device_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "feedback" ADD CONSTRAINT "feedback_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "global_user_medal_progress" ADD CONSTRAINT "global_user_medal_progress_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "global_user_medal_progress" ADD CONSTRAINT "global_user_medal_progress_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "global_user_medals" ADD CONSTRAINT "global_user_medals_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "global_user_medals" ADD CONSTRAINT "global_user_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_user_medal_progress" ADD CONSTRAINT "org_user_medal_progress_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "org_user_medal_progress" ADD CONSTRAINT "org_user_medal_progress_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_user_medals" ADD CONSTRAINT "org_user_medals_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "org_user_medals" ADD CONSTRAINT "org_user_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "session_tokens" ADD CONSTRAINT "session_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") DEFERRABLE; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions_meta" ADD CONSTRAINT "transactions_meta_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entities_postcodes" ADD CONSTRAINT "entities_postcodes_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entities_postcodes" ADD CONSTRAINT "entities_postcodes_fk_outcode_incode" FOREIGN KEY ("outcode", "incode") + REFERENCES "gb_postcodes" ("outcode", "incode") DEFERRABLE; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "leaderboard_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_type_id" FOREIGN KEY ("type_id") + REFERENCES "organisation_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_social_type_id" FOREIGN KEY ("social_type_id") + REFERENCES "organisation_social_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions_external" ADD CONSTRAINT "transactions_external_fk_external_reference_id" FOREIGN KEY ("external_reference_id") + REFERENCES "external_references" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions_external" ADD CONSTRAINT "transactions_external_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "device_subscriptions" ADD CONSTRAINT "device_subscriptions_fk_device_token_id" FOREIGN KEY ("device_token_id") + REFERENCES "device_tokens" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "device_subscriptions" ADD CONSTRAINT "device_subscriptions_fk_topic_id" FOREIGN KEY ("topic_id") + REFERENCES "topics" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisation_payroll" ADD CONSTRAINT "organisation_payroll_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") DEFERRABLE; + +; +ALTER TABLE "organisations_external" ADD CONSTRAINT "organisations_external_fk_external_reference_id" FOREIGN KEY ("external_reference_id") + REFERENCES "external_references" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations_external" ADD CONSTRAINT "organisations_external_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; diff --git a/share/ddl/PostgreSQL/upgrade/32-33/001-auto.sql b/share/ddl/PostgreSQL/upgrade/32-33/001-auto.sql new file mode 100644 index 0000000..7e857e5 --- /dev/null +++ b/share/ddl/PostgreSQL/upgrade/32-33/001-auto.sql @@ -0,0 +1,34 @@ +-- Convert schema 'share/ddl/_source/deploy/32/001-auto.yml' to 'share/ddl/_source/deploy/33/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE "device_subscriptions" ( + "id" serial NOT NULL, + "device_token_id" integer NOT NULL, + "topic_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "device_subscriptions_idx_device_token_id" on "device_subscriptions" ("device_token_id"); +CREATE INDEX "device_subscriptions_idx_topic_id" on "device_subscriptions" ("topic_id"); + +; +CREATE TABLE "topics" ( + "id" serial NOT NULL, + "name" character varying(200) NOT NULL, + PRIMARY KEY ("id") +); + +; +ALTER TABLE "device_subscriptions" ADD CONSTRAINT "device_subscriptions_fk_device_token_id" FOREIGN KEY ("device_token_id") + REFERENCES "device_tokens" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "device_subscriptions" ADD CONSTRAINT "device_subscriptions_fk_topic_id" FOREIGN KEY ("topic_id") + REFERENCES "topics" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; + +COMMIT; + diff --git a/share/ddl/SQLite/deploy/33/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/33/001-auto-__VERSION.sql new file mode 100644 index 0000000..51d5a18 --- /dev/null +++ b/share/ddl/SQLite/deploy/33/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Mon Nov 30 14:29:37 2020 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE dbix_class_deploymenthandler_versions ( + id INTEGER PRIMARY KEY NOT NULL, + version varchar(50) NOT NULL, + ddl text, + upgrade_sql text +); +CREATE UNIQUE INDEX dbix_class_deploymenthandler_versions_version ON dbix_class_deploymenthandler_versions (version); +COMMIT; diff --git a/share/ddl/SQLite/deploy/33/001-auto.sql b/share/ddl/SQLite/deploy/33/001-auto.sql new file mode 100644 index 0000000..547f2a3 --- /dev/null +++ b/share/ddl/SQLite/deploy/33/001-auto.sql @@ -0,0 +1,500 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Mon Nov 30 14:29:37 2020 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: account_tokens +-- +CREATE TABLE account_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + name text NOT NULL, + used integer NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX account_tokens_name ON account_tokens (name); +-- +-- Table: category +-- +CREATE TABLE category ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + line_icon varchar(255) +); +CREATE UNIQUE INDEX category_name ON category (name); +-- +-- Table: entities +-- +CREATE TABLE entities ( + id INTEGER PRIMARY KEY NOT NULL, + type varchar(255) NOT NULL +); +-- +-- Table: external_references +-- +CREATE TABLE external_references ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX external_references_name ON external_references (name); +-- +-- Table: gb_wards +-- +CREATE TABLE gb_wards ( + id INTEGER PRIMARY KEY NOT NULL, + ward varchar(100) NOT NULL +); +-- +-- Table: global_medal_group +-- +CREATE TABLE global_medal_group ( + id INTEGER PRIMARY KEY NOT NULL, + group_name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX global_medal_group_group_name ON global_medal_group (group_name); +-- +-- Table: import_sets +-- +CREATE TABLE import_sets ( + id INTEGER PRIMARY KEY NOT NULL, + date datetime NOT NULL +); +-- +-- Table: leaderboards +-- +CREATE TABLE leaderboards ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + type varchar(255) NOT NULL +); +CREATE UNIQUE INDEX leaderboards_type ON leaderboards (type); +-- +-- Table: org_medal_group +-- +CREATE TABLE org_medal_group ( + id INTEGER PRIMARY KEY NOT NULL, + group_name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX org_medal_group_group_name ON org_medal_group (group_name); +-- +-- Table: organisation_social_types +-- +CREATE TABLE organisation_social_types ( + id INTEGER PRIMARY KEY NOT NULL, + key varchar(255) NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX organisation_social_types_key ON organisation_social_types (key); +-- +-- Table: organisation_types +-- +CREATE TABLE organisation_types ( + id INTEGER PRIMARY KEY NOT NULL, + key varchar(255) NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX organisation_types_key ON organisation_types (key); +-- +-- Table: topics +-- +CREATE TABLE topics ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(200) NOT NULL +); +-- +-- Table: customers +-- +CREATE TABLE customers ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + display_name varchar(255) NOT NULL, + full_name varchar(255) NOT NULL, + year_of_birth integer NOT NULL, + postcode varchar(16) NOT NULL, + latitude decimal(5,2), + longitude decimal(5,2), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX customers_idx_entity_id ON customers (entity_id); +-- +-- Table: entity_association +-- +CREATE TABLE entity_association ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + lis boolean, + esta boolean, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX entity_association_idx_entity_id ON entity_association (entity_id); +-- +-- Table: gb_postcodes +-- +CREATE TABLE gb_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL DEFAULT '', + latitude decimal(7,5), + longitude decimal(7,5), + ward_id integer, + PRIMARY KEY (outcode, incode), + FOREIGN KEY (ward_id) REFERENCES gb_wards(id) +); +CREATE INDEX gb_postcodes_idx_ward_id ON gb_postcodes (ward_id); +-- +-- Table: global_medals +-- +CREATE TABLE global_medals ( + id INTEGER PRIMARY KEY NOT NULL, + group_id integer NOT NULL, + threshold integer NOT NULL, + points integer NOT NULL, + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_medals_idx_group_id ON global_medals (group_id); +-- +-- Table: leaderboard_sets +-- +CREATE TABLE leaderboard_sets ( + id INTEGER PRIMARY KEY NOT NULL, + leaderboard_id integer NOT NULL, + date datetime NOT NULL, + FOREIGN KEY (leaderboard_id) REFERENCES leaderboards(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_sets_idx_leaderboard_id ON leaderboard_sets (leaderboard_id); +-- +-- Table: org_medals +-- +CREATE TABLE org_medals ( + id INTEGER PRIMARY KEY NOT NULL, + group_id integer NOT NULL, + threshold integer NOT NULL, + points integer NOT NULL, + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_medals_idx_group_id ON org_medals (group_id); +-- +-- Table: transactions +-- +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + essential boolean NOT NULL DEFAULT false, + distance numeric(15), + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transactions_idx_buyer_id ON transactions (buyer_id); +CREATE INDEX transactions_idx_seller_id ON transactions (seller_id); +-- +-- Table: users +-- +CREATE TABLE users ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + email text NOT NULL, + join_date datetime NOT NULL, + password varchar(100) NOT NULL, + is_admin boolean NOT NULL DEFAULT false, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX users_idx_entity_id ON users (entity_id); +CREATE UNIQUE INDEX users_email ON users (email); +-- +-- Table: device_tokens +-- +CREATE TABLE device_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + token varchar(200) NOT NULL, + register_date datetime NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX device_tokens_idx_user_id ON device_tokens (user_id); +-- +-- Table: feedback +-- +CREATE TABLE feedback ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + submitted_at datetime NOT NULL, + feedbacktext text NOT NULL, + app_name varchar(255) NOT NULL, + package_name varchar(255) NOT NULL, + version_code varchar(255) NOT NULL, + version_number varchar(255) NOT NULL, + actioned boolean NOT NULL DEFAULT false, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX feedback_idx_user_id ON feedback (user_id); +-- +-- Table: global_user_medal_progress +-- +CREATE TABLE global_user_medal_progress ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + total integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_user_medal_progress_idx_entity_id ON global_user_medal_progress (entity_id); +CREATE INDEX global_user_medal_progress_idx_group_id ON global_user_medal_progress (group_id); +-- +-- Table: global_user_medals +-- +CREATE TABLE global_user_medals ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + points integer NOT NULL, + awarded_at datetime NOT NULL, + threshold integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_user_medals_idx_entity_id ON global_user_medals (entity_id); +CREATE INDEX global_user_medals_idx_group_id ON global_user_medals (group_id); +-- +-- Table: import_lookups +-- +CREATE TABLE import_lookups ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + name varchar(255) NOT NULL, + entity_id integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_lookups_idx_entity_id ON import_lookups (entity_id); +CREATE INDEX import_lookups_idx_set_id ON import_lookups (set_id); +-- +-- Table: org_user_medal_progress +-- +CREATE TABLE org_user_medal_progress ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + total integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_user_medal_progress_idx_entity_id ON org_user_medal_progress (entity_id); +CREATE INDEX org_user_medal_progress_idx_group_id ON org_user_medal_progress (group_id); +-- +-- Table: org_user_medals +-- +CREATE TABLE org_user_medals ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + points integer NOT NULL, + awarded_at datetime NOT NULL, + threshold integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_user_medals_idx_entity_id ON org_user_medals (entity_id); +CREATE INDEX org_user_medals_idx_group_id ON org_user_medals (group_id); +-- +-- Table: session_tokens +-- +CREATE TABLE session_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + token varchar(255) NOT NULL, + user_id integer NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX session_tokens_idx_user_id ON session_tokens (user_id); +CREATE UNIQUE INDEX session_tokens_token ON session_tokens (token); +-- +-- Table: transaction_recurring +-- +CREATE TABLE transaction_recurring ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + start_time datetime NOT NULL, + last_updated datetime, + essential boolean NOT NULL DEFAULT false, + distance numeric(15), + category_id integer, + recurring_period varchar(255) NOT NULL, + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (category_id) REFERENCES category(id), + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transaction_recurring_idx_buyer_id ON transaction_recurring (buyer_id); +CREATE INDEX transaction_recurring_idx_category_id ON transaction_recurring (category_id); +CREATE INDEX transaction_recurring_idx_seller_id ON transaction_recurring (seller_id); +-- +-- Table: transactions_meta +-- +CREATE TABLE transactions_meta ( + id INTEGER PRIMARY KEY NOT NULL, + transaction_id integer NOT NULL, + net_value numeric(100,0) NOT NULL, + sales_tax_value numeric(100,0) NOT NULL, + gross_value numeric(100,0) NOT NULL, + local_service boolean NOT NULL DEFAULT false, + regional_service boolean NOT NULL DEFAULT false, + national_service boolean NOT NULL DEFAULT false, + private_household_rebate boolean NOT NULL DEFAULT false, + business_tax_and_rebate boolean NOT NULL DEFAULT false, + stat_loc_gov boolean NOT NULL DEFAULT false, + central_loc_gov boolean NOT NULL DEFAULT false, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); +CREATE INDEX transactions_meta_idx_transaction_id ON transactions_meta (transaction_id); +-- +-- Table: entities_postcodes +-- +CREATE TABLE entities_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL, + entity_id integer NOT NULL, + PRIMARY KEY (outcode, incode, entity_id), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE, + FOREIGN KEY (outcode, incode) REFERENCES gb_postcodes(outcode, incode) +); +CREATE INDEX entities_postcodes_idx_entity_id ON entities_postcodes (entity_id); +CREATE INDEX entities_postcodes_idx_outcode_incode ON entities_postcodes (outcode, incode); +-- +-- Table: import_values +-- +CREATE TABLE import_values ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + user_name varchar(255) NOT NULL, + purchase_date datetime NOT NULL, + purchase_value varchar(255) NOT NULL, + org_name varchar(255) NOT NULL, + transaction_id integer, + ignore_value boolean NOT NULL DEFAULT false, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_values_idx_set_id ON import_values (set_id); +CREATE INDEX import_values_idx_transaction_id ON import_values (transaction_id); +-- +-- Table: leaderboard_values +-- +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_values_idx_entity_id ON leaderboard_values (entity_id); +CREATE INDEX leaderboard_values_idx_set_id ON leaderboard_values (set_id); +CREATE UNIQUE INDEX leaderboard_values_entity_id_set_id ON leaderboard_values (entity_id, set_id); +-- +-- Table: organisations +-- +CREATE TABLE organisations ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + name varchar(255) NOT NULL, + street_name text, + town varchar(255) NOT NULL, + postcode varchar(16), + country varchar(255), + sector varchar(1), + pending boolean NOT NULL DEFAULT false, + is_local boolean, + is_fair boolean, + submitted_by_id integer, + latitude decimal(8,5), + longitude decimal(8,5), + type_id integer, + social_type_id integer, + is_anchor boolean NOT NULL DEFAULT FALSE, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE, + FOREIGN KEY (type_id) REFERENCES organisation_types(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (social_type_id) REFERENCES organisation_social_types(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX organisations_idx_entity_id ON organisations (entity_id); +CREATE INDEX organisations_idx_type_id ON organisations (type_id); +CREATE INDEX organisations_idx_social_type_id ON organisations (social_type_id); +-- +-- Table: transaction_category +-- +CREATE TABLE transaction_category ( + category_id integer NOT NULL, + transaction_id integer NOT NULL, + FOREIGN KEY (category_id) REFERENCES category(id) ON DELETE CASCADE, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); +CREATE INDEX transaction_category_idx_category_id ON transaction_category (category_id); +CREATE INDEX transaction_category_idx_transaction_id ON transaction_category (transaction_id); +CREATE UNIQUE INDEX transaction_category_transaction_id ON transaction_category (transaction_id); +-- +-- Table: transactions_external +-- +CREATE TABLE transactions_external ( + id INTEGER PRIMARY KEY NOT NULL, + transaction_id integer NOT NULL, + external_reference_id integer NOT NULL, + external_id varchar(255) NOT NULL, + FOREIGN KEY (external_reference_id) REFERENCES external_references(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX transactions_external_idx_external_reference_id ON transactions_external (external_reference_id); +CREATE INDEX transactions_external_idx_transaction_id ON transactions_external (transaction_id); +CREATE UNIQUE INDEX transactions_external_external_reference_id_external_id ON transactions_external (external_reference_id, external_id); +-- +-- Table: device_subscriptions +-- +CREATE TABLE device_subscriptions ( + id INTEGER PRIMARY KEY NOT NULL, + device_token_id integer NOT NULL, + topic_id integer NOT NULL, + FOREIGN KEY (device_token_id) REFERENCES device_tokens(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (topic_id) REFERENCES topics(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX device_subscriptions_idx_device_token_id ON device_subscriptions (device_token_id); +CREATE INDEX device_subscriptions_idx_topic_id ON device_subscriptions (topic_id); +-- +-- Table: organisation_payroll +-- +CREATE TABLE organisation_payroll ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + submitted_at datetime NOT NULL, + entry_period datetime NOT NULL, + employee_amount integer NOT NULL, + local_employee_amount integer NOT NULL, + gross_payroll numeric(100,0) NOT NULL, + payroll_income_tax numeric(100,0) NOT NULL, + payroll_employee_ni numeric(100,0) NOT NULL, + payroll_employer_ni numeric(100,0) NOT NULL, + payroll_total_pension numeric(100,0) NOT NULL, + payroll_other_benefit numeric(100,0) NOT NULL, + FOREIGN KEY (org_id) REFERENCES organisations(id) +); +CREATE INDEX organisation_payroll_idx_org_id ON organisation_payroll (org_id); +-- +-- Table: organisations_external +-- +CREATE TABLE organisations_external ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + external_reference_id integer NOT NULL, + external_id varchar(255) NOT NULL, + FOREIGN KEY (external_reference_id) REFERENCES external_references(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (org_id) REFERENCES organisations(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX organisations_external_idx_external_reference_id ON organisations_external (external_reference_id); +CREATE INDEX organisations_external_idx_org_id ON organisations_external (org_id); +CREATE UNIQUE INDEX organisations_external_external_reference_id_external_id ON organisations_external (external_reference_id, external_id); +COMMIT; diff --git a/share/ddl/SQLite/upgrade/32-33/001-auto.sql b/share/ddl/SQLite/upgrade/32-33/001-auto.sql new file mode 100644 index 0000000..21b5553 --- /dev/null +++ b/share/ddl/SQLite/upgrade/32-33/001-auto.sql @@ -0,0 +1,30 @@ +-- Convert schema 'share/ddl/_source/deploy/32/001-auto.yml' to 'share/ddl/_source/deploy/33/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE device_subscriptions ( + id INTEGER PRIMARY KEY NOT NULL, + device_token_id integer NOT NULL, + topic_id integer NOT NULL, + FOREIGN KEY (device_token_id) REFERENCES device_tokens(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (topic_id) REFERENCES topics(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); + +; +CREATE INDEX device_subscriptions_idx_device_token_id ON device_subscriptions (device_token_id); + +; +CREATE INDEX device_subscriptions_idx_topic_id ON device_subscriptions (topic_id); + +; +CREATE TABLE topics ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(200) NOT NULL +); + +; + +COMMIT; + diff --git a/share/ddl/_source/deploy/33/001-auto-__VERSION.yml b/share/ddl/_source/deploy/33/001-auto-__VERSION.yml new file mode 100644 index 0000000..7f96b5c --- /dev/null +++ b/share/ddl/_source/deploy/33/001-auto-__VERSION.yml @@ -0,0 +1,91 @@ +--- +schema: + procedures: {} + tables: + dbix_class_deploymenthandler_versions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - version + match_type: '' + name: dbix_class_deploymenthandler_versions_version + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + ddl: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ddl + order: 3 + size: + - 0 + id: + data_type: int + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + upgrade_sql: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: upgrade_sql + order: 4 + size: + - 0 + version: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: version + order: 2 + size: + - 50 + indices: [] + name: dbix_class_deploymenthandler_versions + options: [] + order: 1 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - __VERSION + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 1.61 diff --git a/share/ddl/_source/deploy/33/001-auto.yml b/share/ddl/_source/deploy/33/001-auto.yml new file mode 100644 index 0000000..21c74fb --- /dev/null +++ b/share/ddl/_source/deploy/33/001-auto.yml @@ -0,0 +1,3757 @@ +--- +schema: + procedures: {} + tables: + account_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: account_tokens_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 0 + used: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: used + order: 3 + size: + - 0 + indices: [] + name: account_tokens + options: [] + order: 1 + category: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: category_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + line_icon: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: line_icon + order: 3 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 255 + indices: [] + name: category + options: [] + order: 2 + customers: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: customers_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + display_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: display_name + order: 3 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + full_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 4 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 7 + size: + - 5 + - 2 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 8 + size: + - 5 + - 2 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + year_of_birth: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: year_of_birth + order: 5 + size: + - 0 + indices: + - fields: + - entity_id + name: customers_idx_entity_id + options: [] + type: NORMAL + name: customers + options: [] + order: 13 + device_subscriptions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - device_token_id + match_type: '' + name: device_subscriptions_fk_device_token_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: device_tokens + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - topic_id + match_type: '' + name: device_subscriptions_fk_topic_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: topics + type: FOREIGN KEY + fields: + device_token_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: device_token_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + topic_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: topic_id + order: 3 + size: + - 0 + indices: + - fields: + - device_token_id + name: device_subscriptions_idx_device_token_id + options: [] + type: NORMAL + - fields: + - topic_id + name: device_subscriptions_idx_topic_id + options: [] + type: NORMAL + name: device_subscriptions + options: [] + order: 37 + device_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: device_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + register_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: register_date + order: 4 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: token + order: 3 + size: + - 200 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + indices: + - fields: + - user_id + name: device_tokens_idx_user_id + options: [] + type: NORMAL + name: device_tokens + options: [] + order: 21 + entities: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: type + order: 2 + size: + - 255 + indices: [] + name: entities + options: [] + order: 3 + entities_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + - entity_id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entities_postcodes_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: entities_postcodes_fk_outcode_incode + on_delete: '' + on_update: '' + options: [] + reference_fields: + - outcode + - incode + reference_table: gb_postcodes + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: entity_id + order: 3 + size: + - 0 + incode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + indices: + - fields: + - entity_id + name: entities_postcodes_idx_entity_id + options: [] + type: NORMAL + - fields: + - outcode + - incode + name: entities_postcodes_idx_outcode_incode + options: [] + type: NORMAL + name: entities_postcodes + options: [] + order: 31 + entity_association: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entity_association_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + esta: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: esta + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + lis: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: lis + order: 3 + size: + - 0 + indices: + - fields: + - entity_id + name: entity_association_idx_entity_id + options: [] + type: NORMAL + name: entity_association + options: [] + order: 14 + external_references: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: external_references_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 255 + indices: [] + name: external_references + options: [] + order: 4 + feedback: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: feedback_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + actioned: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: actioned + order: 9 + size: + - 0 + app_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: app_name + order: 5 + size: + - 255 + feedbacktext: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: feedbacktext + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + package_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: package_name + order: 6 + size: + - 255 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + version_code: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_code + order: 7 + size: + - 255 + version_number: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_number + order: 8 + size: + - 255 + indices: + - fields: + - user_id + name: feedback_idx_user_id + options: [] + type: NORMAL + name: feedback + options: [] + order: 22 + gb_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - ward_id + match_type: '' + name: gb_postcodes_fk_ward_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: gb_wards + type: FOREIGN KEY + fields: + incode: + data_type: char + default_value: '' + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 3 + size: + - 7 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 4 + size: + - 7 + - 5 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + ward_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ward_id + order: 5 + size: + - 0 + indices: + - fields: + - ward_id + name: gb_postcodes_idx_ward_id + options: [] + type: NORMAL + name: gb_postcodes + options: [] + order: 15 + gb_wards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ward: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ward + order: 2 + size: + - 100 + indices: [] + name: gb_wards + options: [] + order: 5 + global_medal_group: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - group_name + match_type: '' + name: global_medal_group_group_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + group_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: group_name + order: 2 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: global_medal_group + options: [] + order: 6 + global_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 3 + size: + - 0 + indices: + - fields: + - group_id + name: global_medals_idx_group_id + options: [] + type: NORMAL + name: global_medals + options: [] + order: 16 + global_user_medal_progress: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: global_user_medal_progress_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_user_medal_progress_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + total: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: total + order: 4 + size: + - 0 + indices: + - fields: + - entity_id + name: global_user_medal_progress_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: global_user_medal_progress_idx_group_id + options: [] + type: NORMAL + name: global_user_medal_progress + options: [] + order: 23 + global_user_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: global_user_medals_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_user_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + awarded_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: awarded_at + order: 5 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 6 + size: + - 0 + indices: + - fields: + - entity_id + name: global_user_medals_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: global_user_medals_idx_group_id + options: [] + type: NORMAL + name: global_user_medals + options: [] + order: 24 + import_lookups: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: import_lookups_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_lookups_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + indices: + - fields: + - entity_id + name: import_lookups_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: import_lookups_idx_set_id + options: [] + type: NORMAL + name: import_lookups + options: [] + order: 25 + import_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: import_sets + options: [] + order: 7 + import_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: import_values_fk_transaction_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ignore_value: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ignore_value + order: 8 + size: + - 0 + org_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_name + order: 6 + size: + - 255 + purchase_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_date + order: 4 + size: + - 0 + purchase_value: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_value + order: 5 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 7 + size: + - 0 + user_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_name + order: 3 + size: + - 255 + indices: + - fields: + - set_id + name: import_values_idx_set_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: import_values_idx_transaction_id + options: [] + type: NORMAL + name: import_values + options: [] + order: 32 + leaderboard_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - leaderboard_id + match_type: '' + name: leaderboard_sets_fk_leaderboard_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboards + type: FOREIGN KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + leaderboard_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: leaderboard_id + order: 2 + size: + - 0 + indices: + - fields: + - leaderboard_id + name: leaderboard_sets_idx_leaderboard_id + options: [] + type: NORMAL + name: leaderboard_sets + options: [] + order: 17 + leaderboard_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + - set_id + match_type: '' + name: leaderboard_values_entity_id_set_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - entity_id + match_type: '' + name: leaderboard_values_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: leaderboard_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboard_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + position: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: position + order: 4 + size: + - 0 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: set_id + order: 3 + size: + - 0 + trend: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: trend + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 5 + size: + - 100 + - 0 + indices: + - fields: + - entity_id + name: leaderboard_values_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: leaderboard_values_idx_set_id + options: [] + type: NORMAL + name: leaderboard_values + options: [] + order: 33 + leaderboards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - type + match_type: '' + name: leaderboards_type + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 255 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: type + order: 3 + size: + - 255 + indices: [] + name: leaderboards + options: [] + order: 8 + org_medal_group: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - group_name + match_type: '' + name: org_medal_group_group_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + group_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: group_name + order: 2 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: org_medal_group + options: [] + order: 9 + org_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 3 + size: + - 0 + indices: + - fields: + - group_id + name: org_medals_idx_group_id + options: [] + type: NORMAL + name: org_medals + options: [] + order: 18 + org_user_medal_progress: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: org_user_medal_progress_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_user_medal_progress_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + total: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: total + order: 4 + size: + - 0 + indices: + - fields: + - entity_id + name: org_user_medal_progress_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: org_user_medal_progress_idx_group_id + options: [] + type: NORMAL + name: org_user_medal_progress + options: [] + order: 26 + org_user_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: org_user_medals_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_user_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + awarded_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: awarded_at + order: 5 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 6 + size: + - 0 + indices: + - fields: + - entity_id + name: org_user_medals_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: org_user_medals_idx_group_id + options: [] + type: NORMAL + name: org_user_medals + options: [] + order: 27 + organisation_payroll: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisation_payroll_fk_org_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: employee_amount + order: 5 + size: + - 0 + entry_period: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entry_period + order: 4 + size: + - 0 + gross_payroll: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_payroll + order: 7 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_employee_amount + order: 6 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + payroll_employee_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employee_ni + order: 9 + size: + - 100 + - 0 + payroll_employer_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employer_ni + order: 10 + size: + - 100 + - 0 + payroll_income_tax: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_income_tax + order: 8 + size: + - 100 + - 0 + payroll_other_benefit: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_other_benefit + order: 12 + size: + - 100 + - 0 + payroll_total_pension: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_total_pension + order: 11 + size: + - 100 + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + indices: + - fields: + - org_id + name: organisation_payroll_idx_org_id + options: [] + type: NORMAL + name: organisation_payroll + options: [] + order: 38 + organisation_social_types: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - key + match_type: '' + name: organisation_social_types_key + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + key: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: key + order: 2 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + indices: [] + name: organisation_social_types + options: [] + order: 10 + organisation_types: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - key + match_type: '' + name: organisation_types_key + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + key: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: key + order: 2 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + indices: [] + name: organisation_types + options: [] + order: 11 + organisations: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: organisations_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - type_id + match_type: '' + name: organisations_fk_type_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisation_types + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - social_type_id + match_type: '' + name: organisations_fk_social_type_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisation_social_types + type: FOREIGN KEY + fields: + country: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: country + order: 7 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_anchor: + data_type: boolean + default_value: !!perl/ref + =: FALSE + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_anchor + order: 17 + size: + - 0 + is_fair: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_fair + order: 11 + size: + - 0 + is_local: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_local + order: 10 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 13 + size: + - 8 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 14 + size: + - 8 + - 5 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + pending: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: pending + order: 9 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + sector: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: sector + order: 8 + size: + - 1 + social_type_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: social_type_id + order: 16 + size: + - 0 + street_name: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: street_name + order: 4 + size: + - 0 + submitted_by_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: submitted_by_id + order: 12 + size: + - 0 + town: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: town + order: 5 + size: + - 255 + type_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: type_id + order: 15 + size: + - 0 + indices: + - fields: + - entity_id + name: organisations_idx_entity_id + options: [] + type: NORMAL + - fields: + - type_id + name: organisations_idx_type_id + options: [] + type: NORMAL + - fields: + - social_type_id + name: organisations_idx_social_type_id + options: [] + type: NORMAL + name: organisations + options: [] + order: 34 + organisations_external: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - external_reference_id + - external_id + match_type: '' + name: organisations_external_external_reference_id_external_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - external_reference_id + match_type: '' + name: organisations_external_fk_external_reference_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: external_references + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisations_external_fk_org_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + external_id: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_id + order: 4 + size: + - 255 + external_reference_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_reference_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + indices: + - fields: + - external_reference_id + name: organisations_external_idx_external_reference_id + options: [] + type: NORMAL + - fields: + - org_id + name: organisations_external_idx_org_id + options: [] + type: NORMAL + name: organisations_external + options: [] + order: 39 + session_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - token + match_type: '' + name: session_tokens_token + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: session_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: token + order: 2 + size: + - 255 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 3 + size: + - 0 + indices: + - fields: + - user_id + name: session_tokens_idx_user_id + options: [] + type: NORMAL + name: session_tokens + options: [] + order: 28 + topics: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 200 + indices: [] + name: topics + options: [] + order: 12 + transaction_category: + constraints: + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_transaction_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - category_id + match_type: '' + name: transaction_category_fk_category_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: category + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_fk_transaction_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + category_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: category_id + order: 1 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - category_id + name: transaction_category_idx_category_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: transaction_category_idx_transaction_id + options: [] + type: NORMAL + name: transaction_category + options: [] + order: 35 + transaction_recurring: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transaction_recurring_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - category_id + match_type: '' + name: transaction_recurring_fk_category_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: category + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transaction_recurring_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + category_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: category_id + order: 9 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 8 + size: + - 15 + essential: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: essential + order: 7 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + last_updated: + data_type: datetime + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: last_updated + order: 6 + size: + - 0 + recurring_period: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: recurring_period + order: 10 + size: + - 255 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + start_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: start_time + order: 5 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transaction_recurring_idx_buyer_id + options: [] + type: NORMAL + - fields: + - category_id + name: transaction_recurring_idx_category_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transaction_recurring_idx_seller_id + options: [] + type: NORMAL + name: transaction_recurring + options: [] + order: 29 + transactions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transactions_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transactions_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 9 + size: + - 15 + essential: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: essential + order: 8 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + proof_image: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: proof_image + order: 5 + size: + - 0 + purchase_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_time + order: 7 + size: + - 0 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transactions_idx_buyer_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transactions_idx_seller_id + options: [] + type: NORMAL + name: transactions + options: [] + order: 19 + transactions_external: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - external_reference_id + - external_id + match_type: '' + name: transactions_external_external_reference_id_external_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - external_reference_id + match_type: '' + name: transactions_external_fk_external_reference_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: external_references + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transactions_external_fk_transaction_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + external_id: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_id + order: 4 + size: + - 255 + external_reference_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_reference_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - external_reference_id + name: transactions_external_idx_external_reference_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: transactions_external_idx_transaction_id + options: [] + type: NORMAL + name: transactions_external + options: [] + order: 36 + transactions_meta: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transactions_meta_fk_transaction_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + business_tax_and_rebate: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: business_tax_and_rebate + order: 10 + size: + - 0 + central_loc_gov: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: central_loc_gov + order: 12 + size: + - 0 + gross_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_value + order: 5 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_service + order: 6 + size: + - 0 + national_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: national_service + order: 8 + size: + - 0 + net_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: net_value + order: 3 + size: + - 100 + - 0 + private_household_rebate: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: private_household_rebate + order: 9 + size: + - 0 + regional_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: regional_service + order: 7 + size: + - 0 + sales_tax_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: sales_tax_value + order: 4 + size: + - 100 + - 0 + stat_loc_gov: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: stat_loc_gov + order: 11 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - transaction_id + name: transactions_meta_idx_transaction_id + options: [] + type: NORMAL + name: transactions_meta + options: [] + order: 30 + users: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: users_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: users_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 3 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_admin: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_admin + order: 6 + size: + - 0 + join_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: join_date + order: 4 + size: + - 0 + password: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: password + order: 5 + size: + - 100 + indices: + - fields: + - entity_id + name: users_idx_entity_id + options: [] + type: NORMAL + name: users + options: [] + order: 20 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - AccountToken + - Category + - Customer + - DeviceSubscription + - DeviceToken + - Entity + - EntityAssociation + - EntityPostcode + - ExternalReference + - Feedback + - GbPostcode + - GbWard + - GlobalMedalGroup + - GlobalMedals + - GlobalUserMedalProgress + - GlobalUserMedals + - ImportLookup + - ImportSet + - ImportValue + - Leaderboard + - LeaderboardSet + - LeaderboardValue + - OrgMedalGroup + - OrgMedals + - OrgUserMedalProgress + - OrgUserMedals + - Organisation + - OrganisationExternal + - OrganisationPayroll + - OrganisationSocialType + - OrganisationType + - SessionToken + - Topic + - Transaction + - TransactionCategory + - TransactionExternal + - TransactionMeta + - TransactionRecurring + - User + - ViewQuantisedTransactionCategoryPg + - ViewQuantisedTransactionCategorySQLite + - ViewQuantisedTransactionPg + - ViewQuantisedTransactionSQLite + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 1.61 From 7f2be9ea9f02fcc871ac11932be8c9e4e7a83b41 Mon Sep 17 00:00:00 2001 From: Ben Goldsworthy Date: Tue, 1 Dec 2020 11:47:17 +0000 Subject: [PATCH 261/289] Refactor Devices controller --- lib/Pear/LocalLoop/Controller/Api/Devices.pm | 130 +++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 lib/Pear/LocalLoop/Controller/Api/Devices.pm diff --git a/lib/Pear/LocalLoop/Controller/Api/Devices.pm b/lib/Pear/LocalLoop/Controller/Api/Devices.pm new file mode 100644 index 0000000..c8fcf4c --- /dev/null +++ b/lib/Pear/LocalLoop/Controller/Api/Devices.pm @@ -0,0 +1,130 @@ +package Pear::LocalLoop::Controller::Api::Devices; +use Mojo::Base 'Mojolicious::Controller'; +use LWP::UserAgent; +use JSON; +use Mojo::File; + +has error_messages => sub { + return { + token => { + required => { message => 'Token is required', status => 400 }, + not_in_resultset => { message => 'Token already in database', status => 400 }, + }, + email => { + required => { message => 'User email is required', status => 400 }, + in_resultset => { message => 'User email not recognised', status => 400 }, + }, + }; +}; + +sub check_token { + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + $validation->required('token'); + + my $token = $validation->param('token'); + my $token_rs = $c->schema->resultset('DeviceToken')->search({'token' => $token}); + + if ($token_rs->count > 0) { + return $c->render( json => { + exists => Mojo::JSON->true + }); + } else { + return $c->render( json => { + exists => Mojo::JSON->false + }); + } +} + +sub add_token { + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + my $token_rs = $c->schema->resultset('DeviceToken'); + my $user_rs = $c->schema->resultset('User'); + + # TODO: validate that prexisting tokens are connected to the logged-in user + $validation->required('email')->in_resultset( 'email', $user_rs ); + $validation->required('token')->not_in_resultset( 'token', $token_rs ); + + return $c->api_validation_error if $validation->has_error; + + my $user = $user_rs->find({'email' => $validation->param('email')}); + + my $token = $validation->param('token'); + + $user->create_related( + 'device_tokens', + { + token => $token, + } + ); + + my $end_point = "https://iid.googleapis.com/iid/v1/${token}/rel/topics/default"; + + my $path = './localspend-47012.json'; + my $json = decode_json(Mojo::File->new($path)->slurp); + croak("No Private key in $path") if not defined $json->{server_key}; + croak("Not a service account") if $json->{type} ne 'service_account'; + + my $ua = LWP::UserAgent->new(); + my $request = HTTP::Request->new('POST', $end_point); + + $request->header('Authorization' => 'key='.$json->{server_key}); + $request->header('Content-Length' => '0'); + my $response = $ua->request($request); + + if ($response->is_success) { + my $deviceToken = $c->schema->resultset('DeviceToken')->find({'token' => $token}); + my $topic = $c->schema->resultset('Topic')->find({'name' => 'default'}); + + $deviceToken->create_related( + 'device_subscriptions', + { + topic => $topic + } + ); + + return $c->render( json => { + success => Mojo::JSON->true, + message => 'Device registered successfully!', + }); + } elsif ($response->is_error) { + return $c->render( + json => { + success => Mojo::JSON->false, + message => [ + $response->decoded_content, + ], + error => 'subscription_error', + }, + status => $response->code, + ); + } +} + +sub get_tokens { + my $c = shift; + + my $token_rs = $c->schema->resultset('DeviceToken'); + + my @tokens = ( + map {{ + id => $_->id, + user => $c->schema->resultset('User')->find({'id' => $_->user_id})->entity->customer->display_name, + token => $_->token, + }} $token_rs->all + ); + + return $c->render( json => { + success => Mojo::JSON->true, + tokens => \@tokens, + }); +} + +1; From ca2d1e8aabc26b94d7768e79901e657e22003a5f Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 09:40:32 +0000 Subject: [PATCH 262/289] Update readme --- README.md | 212 +++++++++++++++++++++++++++--------------------------- 1 file changed, 104 insertions(+), 108 deletions(-) diff --git a/README.md b/README.md index 8cf1488..030060a 100644 --- a/README.md +++ b/README.md @@ -1,146 +1,142 @@ -# LocalSpend - Server +# LocalSpend (Server) -This repository contains the server for the LocalSpend system. +Looking to discover if the value of spending local can be measured, understood and shown. -## Current Status - -*Master:* [![Build Status](https://travis-ci.org/Pear-Trading/Foodloop-Server.svg?branch=master)](https://travis-ci.org/Pear-Trading/Foodloop-Server) - -*Development:* [![Build Status](https://travis-ci.org/Pear-Trading/Foodloop-Server.svg?branch=development)](https://travis-ci.org/Pear-Trading/Foodloop-Server) - -# Test Environment +This repository contains the server application for the LocalSpend system. See also: -## Running Tests +* the [Web application](https://github.com/Pear-Trading/Foodloop-Web); and +* the [mobile application](https://github.com/Pear-Trading/LocalSpend-Tracker). -To run the main test framework, first install all the dependencies, then run -the tests: +## Current Status -- `cpanm --installdeps .` -- `prove -lr` +| Branch | Status | +|---------------|------------------ | +| `master` | [![Build Status](https://travis-ci.org/Pear-Trading/Foodloop-Server.svg?branch=master)](https://travis-ci.org/Pear-Trading/Foodloop-Server) | +| `development` | [![Build Status](https://travis-ci.org/Pear-Trading/Foodloop-Server.svg?branch=development)](https://travis-ci.org/Pear-Trading/Foodloop-Server) | -To run the main framework against a PostgreSQL backend, assuming you have -`postgres` installed, you will need some extra dependencies first: +## Table of Contents -- `cpanm --installdeps . --with-feature postgres` -- `PEAR_TEST_PG=1 prove -lr` +* [Tech Stack](#tech-stack) +* [Features](#features) +* [Installation](#installation) +* [Configuration](#configuration) +* [Usage](#usage) +* [Testing](#testing) +* [Code Formatting](#code-formatting) +* [Documentation](#documentation) +* [Acknowledgments](#acknowledgements) +* [License](#license) +* [Contact](#contact) -## Setting Up Minion +## Technology Stack -To set up Minion support, you will need to create a database and user for -it to connect to. -In production his should be a PostgreSQL database, however SQLite can be used -in testing. +The server app. is written in [Perl](https://www.perl.org/). -To use the SQLite version: +| Technology | Description | Link | +|-------------|---------------------|---------------------| +| Mojolicious | Perl Web framework | [Link][mojolicious] | +| PostgreSQL | Relational database | [Linke][postgresql] | -1. Install the SQLite dependencies: - - `cpanm --installdeps --with-feature sqlite .` -2. Ensure that the following is in your configuration file: - - ``` - minion => { - SQLite => 'sqlite:minion.db', - }, - ``` +[mojolicious]: https://mojolicious.org/ +[postgresql]: https://www.postgresql.org/ -This will then use an SQLite DB for the Minion backend, using `minion.db` as -the database file. +## Features -To start the minion itself, run this command: -- `./script/pear-local_loop minion worker` +This server app. provides: -## Importing Ward Data +- user creation, updating and deletion; +- organisation creation, updating and deletion; +- transaction logging; +- transaction history analysis; and +- leaderboard generation. -To import ward data: +## Installation -1. Download CSV(s) from [here](https://www.doogal.co.uk/PostcodeDownloads.php) -1. Run the following command: +1. Clone the repo. to your dev. environment (`git clone git@github.com:Pear-Trading/FoodLoop-Server.git`); +1. enter the new directory (`cd FoodLoop-Server`); +1. install the dependencies: - ```shell script - ./script/pear-local_loop minion job \ - --enqueue 'csv_postcode_import' \ - --args '[ "⟨ path to CSV ⟩ ]' + cpanm --installdeps . \ + --with-feature=sqlite \ + --with-feature=codepoint-open ``` + - if you are using a PostgreSQL database, replace `--with-feature=sqlite` with `--with-feature=postgres`. +1. install the database: + - development supports both SQLite and PostgreSQL, however production uses PostgreSQL; + - for this example we will use SQLite; + - as the default config. is set up for this, no configuration changes are needed initially. + - run `./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db'`. +1. set up the development users: + - `./script/pear-local_loop dev_data --force` + - **DO NOT RUN ON PROD.** +1. start the [minion](https://docs.mojolicious.org/Minion) job queue: + - `./script/pear-local_loop minion worker` +1. import ward data: + 1. Download the CSV(s) from [here](https://www.doogal.co.uk/PostcodeDownloads.php); and + 1. run the following command: + - ```shell script + ./script/pear-local_loop minion job \ + --enqueue 'csv_postcode_import' \ + --args '[ "⟨ path to CSV ⟩ ]' + ``` +1. set up postcodes: + 1. import [Code-Point Open](https://www.ordnancesurvey.co.uk/business-government/products/code-point-open): + - a copy is included in `etc/`; + - run `./script/pear-local_loop codepoint_open --outcodes LA1` + 1. assign postcodes: + - ```shell script + ./script/pear-local_loop minion job \ + --enqueue entity_postcode_lookup + ``` -## Setting Up Entity Postcodes +## Configuration -1. Import Code-Point Open: - - included in `etc/` - - `./script/pear-local_loop codepoint_open --outcodes LA1` -1. Assign postcodes: - - ```shell script - ./script/pear-local_loop minion job \ - --enqueue entity_postcode_lookup - ``` +App. configuration settings are found in `pear-local_loop.⟨environment⟩.conf`. -## Example PostgreSQL setup +[Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/) (FCM) credentials should be placed in a file called `localspend-47012.json` in root. -``` -# Example commands - probably not the best ones -# TODO come back and improve these with proper ownership and DDL rights -sudo -u postgres createuser minion -sudo -u postgres createdb localloop_minion -sudo -u postgres psql -psql=# alter user minion with encrypted password 'abc123'; -psql=# grant all privileges on database localloop_minion to minion; -``` +## Usage -# Development Environment +- Run `morbo script/pear-local_loop -l http://*:3000` to start the server; and +- run `./script/pear-local_loop minion worker` to start the Minion asynchronous job scheduler. -There are a couple of setup steps to getting a development environment ready. +### Database Scripts -## First Time Setup +To upgrade the database after making changes to commit: -1. Decide if you're using SQLite or PostgreSQL locally. - - Development supports both, however production uses PostgreSQL. - - For this example we will use SQLite. - - As the default config. is set up for this, no configuration changes are -needed initially. -1. Install dependencies: - - ```shell script - cpanm --installdeps . \ - --with-feature=sqlite \ - --with-feature=codepoint-open - ``` - - See [Troubleshooting](#troubleshooting) if you encounter difficulties. -1. Install the database: - - `./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db'` -1. Set up the development users: - - `./script/pear-local_loop dev_data --force` - - **DO NOT RUN ON PROD.** -1. Start the minion: - - `./script/pear-local_loop minion worker` -1. Import ward data (see [instructions](#importing-ward-data) above) -1. Set up postcodes (see [instructions](#setting-up-entity-postcodes) above) -1. Set up your `pear-local_loop.⟨environment⟩.conf` file in the project root -1. Ensure you have a copy of the FCM service user credentials saved in the project root (`localspend-47012.json`) -1. Start the application: - - `morbo script/pear-local_loop -l http://*:3000` - - You can modify the host and port as needed. +1. Increment the `$VERSION` number in `lib/Pear/LocalLoop/Schema.pm`; +1. run `./script/deploy_db write_ddl -c 'dbi:SQLite:dbname=foodloop.db'`; and +1. run `./script/deploy_db upgrade -c 'dbi:SQLite:dbname=foodloop.db'`. -## Database Scripts +Run `./script/pear-local_loop recalc_leaderboards` to update the leaderboards. -To upgrade the database after making changes to commit: +## Testing + +- Run `prove -lr` to run the full test suite using [Test-Simple](https://metacpan.org/release/Test-Simple) (when using an SQLite database); and +- run `PEAR_TEST_PG=1 prove -lr` to run the full test suite (when using a PostgreSQL database). + +## Code Formatting -1. Increment the `$VERSION` number in `lib/Pear/LocalLoop/Schema.pm` -1. `./script/deploy_db write_ddl -c 'dbi:SQLite:dbname=foodloop.db'` -1. `./script/deploy_db upgrade -c 'dbi:SQLite:dbname=foodloop.db'` +TODO -To redo leaderboards: +## Documentation -1. `./script/pear-local_loop recalc_leaderboards` +TODO -# Troubleshooting +## Acknowledgements -## ‘Can't write to /usr/local/share/perl/5.30.0 and /usr/local/bin: Installing modules to /home//perl5’ when running `cpanm` commands +LocalLoop is the result of collaboration between the [Small Green Consultancy](http://www.smallgreenconsultancy.co.uk/), [Shadowcat Systems](https://shadow.cat/), [Independent Lancaster](http://www.independent-lancaster.co.uk/) and the [Ethical Small Traders Association](http://www.lancasteresta.org/). -Install `local::lib` by running the following commands: +## License -``` - cpanm --local-lib=~/perl5 local::lib && eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib) -``` +This project is released under the [MIT license](https://mit-license.org/). -You will have to do every time you open a new Terminal window. -To make it permanent, follow [these steps](https://www.cpan.org/modules/by-module/lib/local-lib-2.000018.readme). +## Contact -## ‘Can't load application from file "/script/pear-local_loop": Can't locate Data/UUID.pm in @INC (you may need to install the DATA::UUID module)’ when running server +| Name | Link(s) | +|----------------|-------------------| +| Mark Keating | [Email][mkeating] | +| Michael Hallam | [Email][mhallam] | -Ensure you have run the `cpan --installdeps` command. +[mkeating]: mailto:m.keating@shadowcat.co.uk +[mhallam]: mailto:info@lancasteresta.org From 4677bf0237157f651230a110f593f2fe8dceda93 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 10:24:36 +0000 Subject: [PATCH 263/289] Add Issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 63fd03fb963a1e36d78a310763bb4eaf19846f2b Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 10:24:59 +0000 Subject: [PATCH 264/289] Add contributing and security info, license under MIT --- CONTRIBUTING.md | 32 ++++++++++++++++++++++++++++++++ LICENSE.md | 21 +++++++++++++++++++++ SECURITY.md | 20 ++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.md create mode 100644 SECURITY.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..eef0509 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,32 @@ +This project welcomes contributions! + +Please follow these guidelines when contributing, as it will give your pull +request the best chance of being accepted: + +# Requesting Features/Reporting Bugs + +- To request a new feature or to report a bug, create an + [Issue](https://github.com/Pear-Trading/Foodloop-Server/issues/new). + +# Contributing Code + +- This project uses [Git Flow](https://githubflow.github.io/); +- branch off of `development` to start developing (`git checkout -b `); +- ensure that your new branch has a descriptive name and begins with your username; +- create a remote copy of your new branch (`git push`); +- create a draft [merge request](https://github.com/Pear-Trading/Foodloop-Server/compare); + to merge your branch with `development` — tag any related or to-close Issues; and +- when you think you're finished, un-draft your pull request. + +# Commits + +- This project uses [Conventional Commits](https://www.conventionalcommits.org); and +- keep individual commits as small as possible. + +# Versioning + +- This project uses [Semantic Versioning](https://semver.org/). + +# Translating + +- Translations are welcome! diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..13591ff --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 creativeLabs Lukasz Holeczek. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the Software), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, andor sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..fd334ca --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,20 @@ +# Security Policy + +## Supported Versions + +The following versions of this software are currently being supported with +security updates: + +| Version | Supported | +| ------- | ------------------ | +| 0.x.x | :white_check_mark: | + +## Reporting a Vulnerability + +To securely report a vulnerability, please DO NOT create an Issue on this +repository. + +Please email [Mark Keating][mkeating] privately with the full details of the +vulnerability. + +[mkeating]: mailto:m.keating@shadowcat.co.uk From a8248f654fd320eab39a0d8a338b078a8139e892 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 11:41:18 +0000 Subject: [PATCH 265/289] Update Issue templates, readme --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- README.md | 29 +++++++++++++---------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7..81c7b58 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,7 +2,7 @@ name: Bug report about: Create a report to help us improve title: '' -labels: '' +labels: 'bug' assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7..36014cd 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,7 +2,7 @@ name: Feature request about: Suggest an idea for this project title: '' -labels: '' +labels: 'enhancement' assignees: '' --- diff --git a/README.md b/README.md index 030060a..df4dbd5 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,10 @@ This repository contains the server application for the LocalSpend system. See a The server app. is written in [Perl](https://www.perl.org/). -| Technology | Description | Link | -|-------------|---------------------|---------------------| -| Mojolicious | Perl Web framework | [Link][mojolicious] | -| PostgreSQL | Relational database | [Linke][postgresql] | +| Technology | Description | Link | +|-------------|--------------------------------------|---------------------| +| Mojolicious | Perl Web framework | [Link][mojolicious] | +| PostgreSQL | Relational database managment system | [Link][postgresql] | [mojolicious]: https://mojolicious.org/ [postgresql]: https://www.postgresql.org/ @@ -46,6 +46,7 @@ This server app. provides: - user creation, updating and deletion; - organisation creation, updating and deletion; +- an admin. management portal; - transaction logging; - transaction history analysis; and - leaderboard generation. @@ -62,14 +63,14 @@ This server app. provides: ``` - if you are using a PostgreSQL database, replace `--with-feature=sqlite` with `--with-feature=postgres`. 1. install the database: - - development supports both SQLite and PostgreSQL, however production uses PostgreSQL; - - for this example we will use SQLite; + - run `./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db'`; + - development supports both SQLite and PostgreSQL (production uses PostgreSQL); + - for this example we will use SQLite; so - as the default config. is set up for this, no configuration changes are needed initially. - - run `./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db'`. 1. set up the development users: - `./script/pear-local_loop dev_data --force` - - **DO NOT RUN ON PROD.** -1. start the [minion](https://docs.mojolicious.org/Minion) job queue: + - **DO NOT RUN ON PROD!** +1. start the [Minion](https://docs.mojolicious.org/Minion) job scheduler: - `./script/pear-local_loop minion worker` 1. import ward data: 1. Download the CSV(s) from [here](https://www.doogal.co.uk/PostcodeDownloads.php); and @@ -93,12 +94,14 @@ This server app. provides: App. configuration settings are found in `pear-local_loop.⟨environment⟩.conf`. -[Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/) (FCM) credentials should be placed in a file called `localspend-47012.json` in root. +[Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/) (FCM) credentials should be placed in a file called `localspend-47012.json` in root. This file is not tracked by Git; ask another developer for a copy. + +Default user credentials are found in `lib/Pear/LocalLoop/Command/dev_data.pm`. ## Usage -- Run `morbo script/pear-local_loop -l http://*:3000` to start the server; and -- run `./script/pear-local_loop minion worker` to start the Minion asynchronous job scheduler. +- Run `./script/pear-local_loop minion worker` to start the Minion asynchronous job scheduler; and +- run `morbo script/pear-local_loop -l http://*:3000` to start the server on the specific hostname and port. ### Database Scripts @@ -115,6 +118,8 @@ Run `./script/pear-local_loop recalc_leaderboards` to update the leaderboards. - Run `prove -lr` to run the full test suite using [Test-Simple](https://metacpan.org/release/Test-Simple) (when using an SQLite database); and - run `PEAR_TEST_PG=1 prove -lr` to run the full test suite (when using a PostgreSQL database). +Test files are found in the `t/` directory. + ## Code Formatting TODO From 602a59f1c3aa22ab42d1862564c2ea41ae58cc93 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 11:52:59 +0000 Subject: [PATCH 266/289] Add linting, pass gentle level --- README.md | 6 +++++- cpanfile | 1 + lib/Pear/LocalLoop/Controller/Admin/Reports.pm | 2 +- lib/Pear/LocalLoop/Controller/Admin/Transactions.pm | 2 +- lib/Pear/LocalLoop/Controller/Api/Categories.pm | 2 +- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 2 +- lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm | 2 +- lib/Pear/LocalLoop/Controller/Root.pm | 2 +- lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm | 4 ++-- lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm | 3 +++ 10 files changed, 17 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index df4dbd5..8685bf1 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,17 @@ This repository contains the server application for the LocalSpend system. See a The server app. is written in [Perl](https://www.perl.org/). +Admin. portal pages are templated using [HTML::EP](https://metacpan.org/pod/distribution/HTML-EP/lib/HTML/EP.pod). + | Technology | Description | Link | |-------------|--------------------------------------|---------------------| | Mojolicious | Perl Web framework | [Link][mojolicious] | | PostgreSQL | Relational database managment system | [Link][postgresql] | +| SQLite | Relational database managment system | [Link][sqlite] | [mojolicious]: https://mojolicious.org/ [postgresql]: https://www.postgresql.org/ +[sqlite]: https://sqlite.org/index.html ## Features @@ -122,7 +126,7 @@ Test files are found in the `t/` directory. ## Code Formatting -TODO +Run `perlcritic lib/` to format all Perl files with [Perl::Critic](https://metacpan.org/pod/Perl::Critic). ## Documentation diff --git a/cpanfile b/cpanfile index 041c680..8c2d742 100644 --- a/cpanfile +++ b/cpanfile @@ -28,6 +28,7 @@ requires 'Text::CSV'; requires 'Try::Tiny'; requires 'Throwable::Error'; requires 'Minion'; +requires 'Perl::Critic'; requires 'WWW::FCM::HTTP'; on 'test' => sub { diff --git a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm index aff6bc9..5d0991f 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm @@ -73,7 +73,7 @@ sub pg_or_sqlite { return \$sqlite_sql; } else { $c->app->log->warn('Unknown Driver Used'); - return undef; + return; } } diff --git a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm index 514f326..bf3056b 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm @@ -113,7 +113,7 @@ sub pg_or_sqlite { return \$sqlite_sql; } else { $c->app->log->warn('Unknown Driver Used'); - return undef; + return; } } diff --git a/lib/Pear/LocalLoop/Controller/Api/Categories.pm b/lib/Pear/LocalLoop/Controller/Api/Categories.pm index 0ffeae7..84bd9c1 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Categories.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Categories.pm @@ -79,7 +79,7 @@ sub pg_or_sqlite { return \$sqlite_sql; } else { $c->app->log->warn('Unknown Driver Used'); - return undef; + return; } } diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index 1b78d8b..d9d127c 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -505,7 +505,7 @@ sub pg_or_sqlite { return \$sqlite_sql; } else { $c->app->log->warn('Unknown Driver Used'); - return undef; + return; } } diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm index f48e52b..2f8e4fc 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm @@ -160,7 +160,7 @@ sub pg_or_sqlite { return \$sqlite_sql; } else { $c->app->log->warn('Unknown Driver Used'); - return undef; + return; } } diff --git a/lib/Pear/LocalLoop/Controller/Root.pm b/lib/Pear/LocalLoop/Controller/Root.pm index ef7b4d3..c2dddba 100644 --- a/lib/Pear/LocalLoop/Controller/Root.pm +++ b/lib/Pear/LocalLoop/Controller/Root.pm @@ -16,7 +16,7 @@ sub under { return 1; } $c->redirect_to('/'); - return undef; + return; } sub auth_login { diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm index a5ba33b..5c94898 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm @@ -13,7 +13,7 @@ sub get_latest { my $type_result = $self->find_by_type( $type ); - return undef unless defined $type_result; + return unless defined $type_result; my $latest = $type_result->search_related('sets', {}, { order_by => { -desc => 'date' }, @@ -29,7 +29,7 @@ sub create_new { my $type_result = $self->find_by_type($type); - return undef unless $type_result; + return unless $type_result; return $type_result->create_new($date); } diff --git a/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm b/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm index a0a789c..9372a9f 100644 --- a/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm +++ b/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm @@ -1,5 +1,8 @@ package Pear::LocalLoop::Schema::Script::DeploymentHandler; +use strict; +use warnings; + use MooX::Options::Actions; use Module::Runtime qw/ use_module /; use DBIx::Class::DeploymentHandler; From 47a55f6322cce52cd1340acba388d1ebeaebd565 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 12:09:50 +0000 Subject: [PATCH 267/289] Add code formatter, format all code --- .gitignore | 1 + README.md | 5 +- lib/Pear/LocalLoop.pm | 642 ++++++----- lib/Pear/LocalLoop/Command/codepoint_open.pm | 84 +- lib/Pear/LocalLoop/Command/dev_data.pm | 155 +-- .../LocalLoop/Command/dev_transactions.pm | 110 +- lib/Pear/LocalLoop/Command/latlong_setup.pm | 106 +- lib/Pear/LocalLoop/Command/leaderboard.pm | 110 +- .../LocalLoop/Command/recalc_leaderboards.pm | 6 +- .../LocalLoop/Command/recur_transactions.pm | 229 ++-- lib/Pear/LocalLoop/Controller/Admin.pm | 82 +- .../LocalLoop/Controller/Admin/Categories.pm | 157 +-- .../LocalLoop/Controller/Admin/Feedback.pm | 68 +- lib/Pear/LocalLoop/Controller/Admin/Import.pm | 560 +++++----- .../LocalLoop/Controller/Admin/ImportFrom.pm | 168 +-- .../Controller/Admin/Organisations.pm | 478 +++++---- .../LocalLoop/Controller/Admin/Reports.pm | 121 +-- lib/Pear/LocalLoop/Controller/Admin/Tokens.pm | 149 +-- .../Controller/Admin/Transactions.pm | 192 ++-- lib/Pear/LocalLoop/Controller/Admin/Users.pm | 290 ++--- lib/Pear/LocalLoop/Controller/Api/Auth.pm | 210 ++-- .../LocalLoop/Controller/Api/Categories.pm | 134 +-- lib/Pear/LocalLoop/Controller/Api/Devices.pm | 228 ++-- lib/Pear/LocalLoop/Controller/Api/External.pm | 900 ++++++++-------- lib/Pear/LocalLoop/Controller/Api/Feedback.pm | 104 +- .../LocalLoop/Controller/Api/Organisation.pm | 466 ++++---- lib/Pear/LocalLoop/Controller/Api/Register.pm | 297 +++--- .../LocalLoop/Controller/Api/Sendmessage.pm | 250 +++-- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 995 ++++++++++-------- .../LocalLoop/Controller/Api/Transactions.pm | 333 +++--- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 529 ++++++---- lib/Pear/LocalLoop/Controller/Api/User.pm | 403 ++++--- .../LocalLoop/Controller/Api/V1/Customer.pm | 22 +- .../Controller/Api/V1/Customer/Graphs.pm | 276 ++--- .../Controller/Api/V1/Customer/Pies.pm | 117 +- .../Controller/Api/V1/Customer/Snippets.pm | 43 +- .../Controller/Api/V1/Organisation.pm | 22 +- .../Controller/Api/V1/Organisation/Graphs.pm | 326 +++--- .../Controller/Api/V1/Organisation/Pies.pm | 117 +- .../Api/V1/Organisation/Snippets.pm | 133 +-- .../Controller/Api/V1/Supplier/Location.pm | 360 ++++--- .../Controller/Api/V1/User/Medals.pm | 72 +- .../Controller/Api/V1/User/Points.pm | 52 +- lib/Pear/LocalLoop/Controller/Portal.pm | 6 +- lib/Pear/LocalLoop/Controller/Root.pm | 43 +- lib/Pear/LocalLoop/Error.pm | 7 +- lib/Pear/LocalLoop/ImplementationError.pm | 8 + lib/Pear/LocalLoop/Import/LCCCsv.pm | 15 +- lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm | 45 +- lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm | 75 +- .../LocalLoop/Import/LCCCsv/Transactions.pm | 256 +++-- lib/Pear/LocalLoop/Import/Role/CSV.pm | 100 +- .../LocalLoop/Import/Role/ExternalName.pm | 13 +- lib/Pear/LocalLoop/Import/Role/Schema.pm | 6 +- .../LocalLoop/Plugin/BootstrapPagination.pm | 242 +++-- lib/Pear/LocalLoop/Plugin/Currency.pm | 35 +- lib/Pear/LocalLoop/Plugin/Datetime.pm | 127 ++- lib/Pear/LocalLoop/Plugin/Minion.pm | 56 +- lib/Pear/LocalLoop/Plugin/Minion/Job.pm | 4 +- .../Plugin/Minion/Job/csv_postcode_import.pm | 10 +- .../Plugin/Minion/Job/csv_supplier_import.pm | 10 +- .../Minion/Job/csv_transaction_import.pm | 12 +- .../Minion/Job/entity_postcode_lookup.pm | 41 +- .../Plugin/Minion/Job/leaderboards_recalc.pm | 6 +- lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm | 10 +- lib/Pear/LocalLoop/Plugin/Postcodes.pm | 114 +- lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm | 21 +- lib/Pear/LocalLoop/Plugin/Validators.pm | 311 +++--- lib/Pear/LocalLoop/Schema.pm | 2 +- .../LocalLoop/Schema/Result/AccountToken.pm | 14 +- lib/Pear/LocalLoop/Schema/Result/Category.pm | 50 +- lib/Pear/LocalLoop/Schema/Result/Customer.pm | 89 +- .../Schema/Result/DeviceSubscription.pm | 46 +- .../LocalLoop/Schema/Result/DeviceToken.pm | 68 +- lib/Pear/LocalLoop/Schema/Result/Entity.pm | 138 ++- .../Schema/Result/EntityAssociation.pm | 47 +- .../LocalLoop/Schema/Result/EntityPostcode.pm | 49 +- .../Schema/Result/ExternalReference.pm | 36 +- lib/Pear/LocalLoop/Schema/Result/Feedback.pm | 134 +-- .../LocalLoop/Schema/Result/GbPostcode.pm | 63 +- lib/Pear/LocalLoop/Schema/Result/GbWard.pm | 28 +- .../Schema/Result/GlobalMedalGroup.pm | 30 +- .../LocalLoop/Schema/Result/GlobalMedals.pm | 42 +- .../Schema/Result/GlobalUserMedalProgress.pm | 49 +- .../Schema/Result/GlobalUserMedals.pm | 77 +- .../LocalLoop/Schema/Result/ImportLookup.pm | 72 +- lib/Pear/LocalLoop/Schema/Result/ImportSet.pm | 46 +- .../LocalLoop/Schema/Result/ImportValue.pm | 114 +- .../LocalLoop/Schema/Result/Leaderboard.pm | 357 ++++--- .../LocalLoop/Schema/Result/LeaderboardSet.pm | 62 +- .../Schema/Result/LeaderboardValue.pm | 94 +- .../LocalLoop/Schema/Result/OrgMedalGroup.pm | 30 +- lib/Pear/LocalLoop/Schema/Result/OrgMedals.pm | 42 +- .../Schema/Result/OrgUserMedalProgress.pm | 49 +- .../LocalLoop/Schema/Result/OrgUserMedals.pm | 77 +- .../LocalLoop/Schema/Result/Organisation.pm | 268 +++-- .../Schema/Result/OrganisationExternal.pm | 56 +- .../Schema/Result/OrganisationPayroll.pm | 131 ++- .../Schema/Result/OrganisationSocialType.pm | 40 +- .../Schema/Result/OrganisationType.pm | 40 +- .../LocalLoop/Schema/Result/SessionToken.pm | 40 +- lib/Pear/LocalLoop/Schema/Result/Topic.pm | 45 +- .../LocalLoop/Schema/Result/Transaction.pm | 136 +-- .../Schema/Result/TransactionCategory.pm | 34 +- .../Schema/Result/TransactionExternal.pm | 54 +- .../Schema/Result/TransactionMeta.pm | 50 +- .../Schema/Result/TransactionRecurring.pm | 134 +-- lib/Pear/LocalLoop/Schema/Result/User.pm | 216 ++-- .../ViewQuantisedTransactionCategoryPg.pm | 6 +- .../ViewQuantisedTransactionCategorySQLite.pm | 6 +- .../Result/ViewQuantisedTransactionPg.pm | 22 +- .../Result/ViewQuantisedTransactionSQLite.pm | 22 +- .../LocalLoop/Schema/ResultSet/Category.pm | 36 +- lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm | 14 +- .../LocalLoop/Schema/ResultSet/ImportSet.pm | 120 +-- .../LocalLoop/Schema/ResultSet/Leaderboard.pm | 136 +-- .../Schema/ResultSet/Organisation.pm | 2 +- .../LocalLoop/Schema/ResultSet/Transaction.pm | 56 +- .../Schema/Script/DeploymentHandler.pm | 147 +-- lib/Test/Pear/LocalLoop.pm | 309 +++--- 120 files changed, 8397 insertions(+), 7303 deletions(-) create mode 100644 lib/Pear/LocalLoop/ImplementationError.pm diff --git a/.gitignore b/.gitignore index 3d4ea4b..7ffaa78 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ hypnotoad.pid *.db-wal *.db-shm *.db-journal +*.bak *~ /images *.swp diff --git a/README.md b/README.md index 8685bf1..7bcca11 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,10 @@ Test files are found in the `t/` directory. ## Code Formatting -Run `perlcritic lib/` to format all Perl files with [Perl::Critic](https://metacpan.org/pod/Perl::Critic). +Run `for f in ./lib/**/*.pm; do perltidy -b $f; done` to format all Perl files +with [Perl-Tidy](https://metacpan.org/release/Perl-Tidy). + +Run `perlcritic lib` to lint all Perl files with [Perl-Critic](https://metacpan.org/release/Perl-Critic). ## Documentation diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 20dae07..5f04a65 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -9,306 +9,380 @@ use Mojo::Asset::File; use Mojo::File qw/ path tempdir /; has schema => sub { - my $c = shift; - return Pear::LocalLoop::Schema->connect( - $c->app->config->{dsn}, - $c->app->config->{user}, - $c->app->config->{pass}, - { quote_names => 1 }, - ); + my $c = shift; + return Pear::LocalLoop::Schema->connect( + $c->app->config->{dsn}, $c->app->config->{user}, + $c->app->config->{pass}, { quote_names => 1 }, + ); }; sub startup { - my $self = shift; - - my $version = `git describe --tags`; - - $self->plugin('Config', { - default => { - storage_path => tempdir, - upload_path => $self->home->child('upload'), - sessionTimeSeconds => 60 * 60 * 24 * 7, - sessionTokenJsonName => 'session_key', - sessionExpiresJsonName => 'sessionExpires', - version => $version, - }, - }); - 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 } ); - $self->plugin('Pear::LocalLoop::Plugin::Validators'); - $self->plugin('Pear::LocalLoop::Plugin::Datetime'); - $self->plugin('Pear::LocalLoop::Plugin::Currency'); - $self->plugin('Pear::LocalLoop::Plugin::Postcodes'); - $self->plugin('Pear::LocalLoop::Plugin::TemplateHelpers'); - $self->plugin('Pear::LocalLoop::Plugin::Minion'); - - $self->plugin('Authentication' => { - 'load_user' => sub { - my ( $c, $user_id ) = @_; - return $c->schema->resultset('User')->find($user_id); - }, - 'validate_user' => sub { - my ( $c, $email, $password, $args) = @_; - my $user = $c->schema->resultset('User')->find({email => $email}); - if ( defined $user ) { - if ( $user->check_password( $password ) ) { - return $user->id; + my $self = shift; + + my $version = `git describe --tags`; + + $self->plugin( + 'Config', + { + default => { + storage_path => tempdir, + upload_path => $self->home->child('upload'), + sessionTimeSeconds => 60 * 60 * 24 * 7, + sessionTokenJsonName => 'session_key', + sessionExpiresJsonName => 'sessionExpires', + version => $version, + }, } - } - return; - }, - }); + ); + my $config = $self->config; - # shortcut for use in template - $self->helper( db => sub { warn "DEPRECATED db helper"; return $self->app->schema->storage->dbh }); - $self->helper( schema => sub { $self->app->schema }); + if ( defined $config->{secret} ) { + $self->secrets( [ $config->{secret} ] ); + } + elsif ( $self->mode eq 'production' ) { - $self->helper( api_validation_error => sub { - my $c = shift; - my $failed_vals = $c->validation->failed; - for my $val ( @$failed_vals ) { - my $check = shift @{ $c->validation->error($val) }; - return $c->render( - json => { - success => Mojo::JSON->false, - message => $c->error_messages->{$val}->{$check}->{message}, - error => $c->error_messages->{$val}->{$check}->{error} || $check, - }, - status => $c->error_messages->{$val}->{$check}->{status}, - ); + # Just incase we end up in production and it hasnt been set! + $self->secrets( [ Data::UUID->new->create() ] ); } - }); - $self->helper( get_path_from_uuid => sub { - my $c = shift; - my $uuid = shift; - my ( $folder ) = $uuid =~ /(..)/; - return path($c->app->config->{storage_path}, $folder, $uuid); - }); + push @{ $self->commands->namespaces }, __PACKAGE__ . '::Command'; + + $self->plugin( 'Pear::LocalLoop::Plugin::BootstrapPagination', + { bootstrap4 => 1 } ); + $self->plugin('Pear::LocalLoop::Plugin::Validators'); + $self->plugin('Pear::LocalLoop::Plugin::Datetime'); + $self->plugin('Pear::LocalLoop::Plugin::Currency'); + $self->plugin('Pear::LocalLoop::Plugin::Postcodes'); + $self->plugin('Pear::LocalLoop::Plugin::TemplateHelpers'); + $self->plugin('Pear::LocalLoop::Plugin::Minion'); + + $self->plugin( + 'Authentication' => { + 'load_user' => sub { + my ( $c, $user_id ) = @_; + return $c->schema->resultset('User')->find($user_id); + }, + 'validate_user' => sub { + my ( $c, $email, $password, $args ) = @_; + my $user = + $c->schema->resultset('User')->find( { email => $email } ); + if ( defined $user ) { + if ( $user->check_password($password) ) { + return $user->id; + } + } + return; + }, + } + ); - $self->helper( store_file_from_upload => sub { - my $c = shift; - my $upload = shift; - my $uuid = Data::UUID->new->create_str; - my $path = $c->get_path_from_uuid( $uuid ); - $path->dirname->make_path; - $upload->move_to( $path ); - return $uuid; - }); - - $self->helper( get_file_from_uuid => sub { - my $c = shift; - my $uuid = shift; - return Mojo::Asset::File->new( path => $c->get_path_from_uuid( $uuid ) ); - }); - - my $r = $self->routes; - $r->get('/')->to('root#index'); - $r->get('/admin')->to('admin#index'); - $r->post('/admin')->to('admin#auth_login'); -# $r->get('/register')->to('register#index'); -# $r->post('/register')->to('register#register'); - $r->any('/admin/logout')->to('admin#auth_logout'); - - my $api_public_get = $r->under('/api' => sub { - my $c = shift; - $c->res->headers->header('Access-Control-Allow-Origin'=> '*'); - $c->res->headers->header('Access-Control-Allow-Credentials' => 'true'); - $c->res->headers->header('Access-Control-Allow-Methods' => 'GET, OPTIONS, POST, DELETE, PUT'); - $c->res->headers->header('Access-Control-Allow-Headers' => 'Content-Type, X-CSRF-Token'); - $c->res->headers->header('Access-Control-Max-Age' => '1728000'); - }); - - $api_public_get->options('*' => sub { - my $c = shift; - $c->respond_to(any => { data => '', status => 200 }); - }); - - # Always available api routes - my $api_public = $api_public_get->under('/')->to('api-auth#check_json'); - - $api_public->post('/test-connection')->to('api-auth#test_connection'); - $api_public->post('/login')->to('api-auth#post_login'); - $api_public->post('/register')->to('api-register#post_register'); - $api_public->post('/logout')->to('api-auth#post_logout'); - $api_public->post('/feedback')->to('api-feedback#post_feedback'); - $api_public->post('/check-device-token')->to('api-devices#check_token'); - $api_public->post('/add-device-token')->to('api-devices#add_token'); - $api_public->post('/get-topics')->to('api-sendmessage#get_topics'); - $api_public->post('/get-device-tokens')->to('api-devices#get_tokens'); - $api_public->post('/send-message')->to('api-sendmessage#post_message'); - - # Private, must be authenticated api routes - my $api = $api_public->under('/')->to('api-auth#auth'); - - $api->post('/' => sub { - return shift->render( json => { - success => Mojo::JSON->true, - message => 'Successful Auth', - }); - }); - $api->post('/upload')->to('api-upload#post_upload'); - $api->post('/search')->to('api-upload#post_search'); - $api->post('/search/category')->to('api-upload#post_category'); - $api->post('/user')->to('api-user#post_account'); - $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/organisation')->to('api-stats#post_organisation'); - $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'); - - my $api_v1_user = $api_v1->under('/user'); - - $api_v1_user->post('/medals')->to('api-v1-user-medals#index'); - $api_v1_user->post('/points')->to('api-v1-user-points#index'); - - my $api_v1_supplier = $api_v1->under('/supplier'); - - $api_v1_supplier->post('/location')->to('api-v1-supplier-location#index'); - $api_v1_supplier->post('/location/trail')->to('api-v1-supplier-location#trail_load'); - - my $api_v1_org = $api_v1->under('/organisation')->to('api-v1-organisation#auth'); - - $api_v1_org->post('/graphs')->to('api-v1-organisation-graphs#index'); - $api_v1_org->post('/snippets')->to('api-v1-organisation-snippets#index'); - $api_v1_org->post('/payroll')->to('api-organisation#post_payroll_read'); - $api_v1_org->post('/payroll/add')->to('api-organisation#post_payroll_add'); - $api_v1_org->post('/supplier')->to('api-organisation#post_supplier_read'); - $api_v1_org->post('/supplier/add')->to('api-organisation#post_supplier_add'); - $api_v1_org->post('/employee')->to('api-organisation#post_employee_read'); - $api_v1_org->post('/employee/add')->to('api-organisation#post_employee_add'); - - $api_v1_org->post('/external/transactions')->to('api-external#post_lcc_transactions'); - $api_v1_org->post('/external/suppliers')->to('api-external#post_lcc_suppliers'); - $api_v1_org->post('/external/year_spend')->to('api-external#post_year_spend'); - $api_v1_org->post('/external/supplier_count')->to('api-external#post_supplier_count'); - $api_v1_org->post('/external/supplier_history')->to('api-external#post_supplier_history'); - $api_v1_org->post('/external/lcc_tables')->to('api-external#post_lcc_table_summary'); - - $api_v1_org->post('/pies')->to('api-v1-organisation-pies#index'); - - my $api_v1_cust = $api_v1->under('/customer')->to('api-v1-customer#auth'); - - $api_v1_cust->post('/graphs')->to('api-v1-customer-graphs#index'); - $api_v1_cust->post('/snippets')->to('api-v1-customer-snippets#index'); - $api_v1_cust->post('/pies')->to('api-v1-customer-pies#index'); - - my $admin_routes = $r->under('/admin')->to('admin#under'); - - if ( defined $config->{minion} ) { - $self->plugin( 'Minion::Admin' => { - return_to => '/admin/home', - route => $admin_routes->any('/minion'), - } ); - } - $admin_routes->get('/home')->to('admin#home'); - - $admin_routes->get('/tokens')->to('admin-tokens#index'); - $admin_routes->post('/tokens')->to('admin-tokens#create'); - $admin_routes->get('/tokens/:id')->to('admin-tokens#read'); - $admin_routes->post('/tokens/:id')->to('admin-tokens#update'); - $admin_routes->post('/tokens/:id/delete')->to('admin-tokens#delete'); - - $admin_routes->get('/categories')->to('admin-categories#index'); - $admin_routes->post('/categories')->to('admin-categories#create'); - $admin_routes->get('/categories/:id')->to('admin-categories#read'); - $admin_routes->post('/categories/:id')->to('admin-categories#update'); - $admin_routes->post('/categories/:id/delete')->to('admin-categories#delete'); - - $admin_routes->get('/users')->to('admin-users#index'); - $admin_routes->get('/users/:id')->to('admin-users#read'); - $admin_routes->post('/users/:id')->to('admin-users#update'); - $admin_routes->post('/users/:id/delete')->to('admin-users#delete'); - - $admin_routes->get('/organisations')->to('admin-organisations#list'); - $admin_routes->get('/organisations/add')->to('admin-organisations#add_org'); - $admin_routes->post('/organisations/add')->to('admin-organisations#add_org_submit'); - $admin_routes->get('/organisations/:id')->to('admin-organisations#valid_read'); - $admin_routes->post('/organisations/:id')->to('admin-organisations#valid_edit'); - $admin_routes->get('/organisations/:id/merge')->to('admin-organisations#merge_list'); - $admin_routes->get('/organisations/:id/merge/:target_id')->to('admin-organisations#merge_detail'); - $admin_routes->post('/organisations/:id/merge/:target_id')->to('admin-organisations#merge_confirm'); - - $admin_routes->get('/feedback')->to('admin-feedback#index'); - $admin_routes->get('/feedback/:id')->to('admin-feedback#read'); - $admin_routes->get('/feedback/:id/actioned')->to('admin-feedback#actioned'); - - $admin_routes->get('/transactions')->to('admin-transactions#index'); - $admin_routes->get('/transactions/:id')->to('admin-transactions#read'); - $admin_routes->get('/transactions/:id/image')->to('admin-transactions#image'); - $admin_routes->post('/transactions/:id/delete')->to('admin-transactions#delete'); - - $admin_routes->get('/reports/transactions')->to('admin-reports#transaction_data'); - - $admin_routes->get('/import')->to('admin-import#index'); - $admin_routes->get('/import/add')->to('admin-import#get_add'); - $admin_routes->post('/import/add')->to('admin-import#post_add'); - $admin_routes->get('/import/:set_id')->to('admin-import#list'); - $admin_routes->get('/import/:set_id/user')->to('admin-import#get_user'); - $admin_routes->get('/import/:set_id/org')->to('admin-import#get_org'); - - $admin_routes->get('/import/:set_id/ignore/:value_id')->to('admin-import#ignore_value'); - $admin_routes->get('/import/:set_id/import')->to('admin-import#run_import'); + # shortcut for use in template + $self->helper( + db => sub { + warn "DEPRECATED db helper"; + return $self->app->schema->storage->dbh; + } + ); + $self->helper( schema => sub { $self->app->schema } ); + + $self->helper( + api_validation_error => sub { + my $c = shift; + my $failed_vals = $c->validation->failed; + for my $val (@$failed_vals) { + my $check = shift @{ $c->validation->error($val) }; + return $c->render( + json => { + success => Mojo::JSON->false, + message => + $c->error_messages->{$val}->{$check}->{message}, + error => $c->error_messages->{$val}->{$check}->{error} + || $check, + }, + status => $c->error_messages->{$val}->{$check}->{status}, + ); + } + } + ); + + $self->helper( + get_path_from_uuid => sub { + my $c = shift; + my $uuid = shift; + my ($folder) = $uuid =~ /(..)/; + return path( $c->app->config->{storage_path}, $folder, $uuid ); + } + ); + + $self->helper( + store_file_from_upload => sub { + my $c = shift; + my $upload = shift; + my $uuid = Data::UUID->new->create_str; + my $path = $c->get_path_from_uuid($uuid); + $path->dirname->make_path; + $upload->move_to($path); + return $uuid; + } + ); + + $self->helper( + get_file_from_uuid => sub { + my $c = shift; + my $uuid = shift; + return Mojo::Asset::File->new( + path => $c->get_path_from_uuid($uuid) ); + } + ); + + my $r = $self->routes; + $r->get('/')->to('root#index'); + $r->get('/admin')->to('admin#index'); + $r->post('/admin')->to('admin#auth_login'); + + # $r->get('/register')->to('register#index'); + # $r->post('/register')->to('register#register'); + $r->any('/admin/logout')->to('admin#auth_logout'); + + my $api_public_get = $r->under( + '/api' => sub { + my $c = shift; + $c->res->headers->header( 'Access-Control-Allow-Origin' => '*' ); + $c->res->headers->header( + 'Access-Control-Allow-Credentials' => 'true' ); + $c->res->headers->header( 'Access-Control-Allow-Methods' => + 'GET, OPTIONS, POST, DELETE, PUT' ); + $c->res->headers->header( 'Access-Control-Allow-Headers' => + 'Content-Type, X-CSRF-Token' ); + $c->res->headers->header( 'Access-Control-Max-Age' => '1728000' ); + } + ); - $admin_routes->get('/import_from')->to('admin-import_from#index'); - $admin_routes->post('/import_from/suppliers')->to('admin-import_from#post_suppliers'); - $admin_routes->post('/import_from/transactions')->to('admin-import_from#post_transactions'); - $admin_routes->post('/import_from/postcodes')->to('admin-import_from#post_postcodes'); - $admin_routes->get('/import_from/org_search')->to('admin-import_from#org_search'); - -# my $user_routes = $r->under('/')->to('root#under'); - -# $user_routes->get('/home')->to('root#home'); + $api_public_get->options( + '*' => sub { + my $c = shift; + $c->respond_to( any => { data => '', status => 200 } ); + } + ); + + # Always available api routes + my $api_public = $api_public_get->under('/')->to('api-auth#check_json'); + + $api_public->post('/test-connection')->to('api-auth#test_connection'); + $api_public->post('/login')->to('api-auth#post_login'); + $api_public->post('/register')->to('api-register#post_register'); + $api_public->post('/logout')->to('api-auth#post_logout'); + $api_public->post('/feedback')->to('api-feedback#post_feedback'); + $api_public->post('/check-device-token')->to('api-devices#check_token'); + $api_public->post('/add-device-token')->to('api-devices#add_token'); + $api_public->post('/get-topics')->to('api-sendmessage#get_topics'); + $api_public->post('/get-device-tokens')->to('api-devices#get_tokens'); + $api_public->post('/send-message')->to('api-sendmessage#post_message'); + + # Private, must be authenticated api routes + my $api = $api_public->under('/')->to('api-auth#auth'); + + $api->post( + '/' => sub { + return shift->render( + json => { + success => Mojo::JSON->true, + message => 'Successful Auth', + } + ); + } + ); + $api->post('/upload')->to('api-upload#post_upload'); + $api->post('/search')->to('api-upload#post_search'); + $api->post('/search/category')->to('api-upload#post_category'); + $api->post('/user')->to('api-user#post_account'); + $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/organisation')->to('api-stats#post_organisation'); + $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'); + + my $api_v1_user = $api_v1->under('/user'); + + $api_v1_user->post('/medals')->to('api-v1-user-medals#index'); + $api_v1_user->post('/points')->to('api-v1-user-points#index'); + + my $api_v1_supplier = $api_v1->under('/supplier'); + + $api_v1_supplier->post('/location')->to('api-v1-supplier-location#index'); + $api_v1_supplier->post('/location/trail') + ->to('api-v1-supplier-location#trail_load'); + + my $api_v1_org = + $api_v1->under('/organisation')->to('api-v1-organisation#auth'); + + $api_v1_org->post('/graphs')->to('api-v1-organisation-graphs#index'); + $api_v1_org->post('/snippets')->to('api-v1-organisation-snippets#index'); + $api_v1_org->post('/payroll')->to('api-organisation#post_payroll_read'); + $api_v1_org->post('/payroll/add')->to('api-organisation#post_payroll_add'); + $api_v1_org->post('/supplier')->to('api-organisation#post_supplier_read'); + $api_v1_org->post('/supplier/add') + ->to('api-organisation#post_supplier_add'); + $api_v1_org->post('/employee')->to('api-organisation#post_employee_read'); + $api_v1_org->post('/employee/add') + ->to('api-organisation#post_employee_add'); + + $api_v1_org->post('/external/transactions') + ->to('api-external#post_lcc_transactions'); + $api_v1_org->post('/external/suppliers') + ->to('api-external#post_lcc_suppliers'); + $api_v1_org->post('/external/year_spend') + ->to('api-external#post_year_spend'); + $api_v1_org->post('/external/supplier_count') + ->to('api-external#post_supplier_count'); + $api_v1_org->post('/external/supplier_history') + ->to('api-external#post_supplier_history'); + $api_v1_org->post('/external/lcc_tables') + ->to('api-external#post_lcc_table_summary'); + + $api_v1_org->post('/pies')->to('api-v1-organisation-pies#index'); + + my $api_v1_cust = $api_v1->under('/customer')->to('api-v1-customer#auth'); + + $api_v1_cust->post('/graphs')->to('api-v1-customer-graphs#index'); + $api_v1_cust->post('/snippets')->to('api-v1-customer-snippets#index'); + $api_v1_cust->post('/pies')->to('api-v1-customer-pies#index'); + + my $admin_routes = $r->under('/admin')->to('admin#under'); + + if ( defined $config->{minion} ) { + $self->plugin( + 'Minion::Admin' => { + return_to => '/admin/home', + route => $admin_routes->any('/minion'), + } + ); + } + $admin_routes->get('/home')->to('admin#home'); + + $admin_routes->get('/tokens')->to('admin-tokens#index'); + $admin_routes->post('/tokens')->to('admin-tokens#create'); + $admin_routes->get('/tokens/:id')->to('admin-tokens#read'); + $admin_routes->post('/tokens/:id')->to('admin-tokens#update'); + $admin_routes->post('/tokens/:id/delete')->to('admin-tokens#delete'); + + $admin_routes->get('/categories')->to('admin-categories#index'); + $admin_routes->post('/categories')->to('admin-categories#create'); + $admin_routes->get('/categories/:id')->to('admin-categories#read'); + $admin_routes->post('/categories/:id')->to('admin-categories#update'); + $admin_routes->post('/categories/:id/delete') + ->to('admin-categories#delete'); + + $admin_routes->get('/users')->to('admin-users#index'); + $admin_routes->get('/users/:id')->to('admin-users#read'); + $admin_routes->post('/users/:id')->to('admin-users#update'); + $admin_routes->post('/users/:id/delete')->to('admin-users#delete'); + + $admin_routes->get('/organisations')->to('admin-organisations#list'); + $admin_routes->get('/organisations/add')->to('admin-organisations#add_org'); + $admin_routes->post('/organisations/add') + ->to('admin-organisations#add_org_submit'); + $admin_routes->get('/organisations/:id') + ->to('admin-organisations#valid_read'); + $admin_routes->post('/organisations/:id') + ->to('admin-organisations#valid_edit'); + $admin_routes->get('/organisations/:id/merge') + ->to('admin-organisations#merge_list'); + $admin_routes->get('/organisations/:id/merge/:target_id') + ->to('admin-organisations#merge_detail'); + $admin_routes->post('/organisations/:id/merge/:target_id') + ->to('admin-organisations#merge_confirm'); + + $admin_routes->get('/feedback')->to('admin-feedback#index'); + $admin_routes->get('/feedback/:id')->to('admin-feedback#read'); + $admin_routes->get('/feedback/:id/actioned')->to('admin-feedback#actioned'); + + $admin_routes->get('/transactions')->to('admin-transactions#index'); + $admin_routes->get('/transactions/:id')->to('admin-transactions#read'); + $admin_routes->get('/transactions/:id/image') + ->to('admin-transactions#image'); + $admin_routes->post('/transactions/:id/delete') + ->to('admin-transactions#delete'); + + $admin_routes->get('/reports/transactions') + ->to('admin-reports#transaction_data'); + + $admin_routes->get('/import')->to('admin-import#index'); + $admin_routes->get('/import/add')->to('admin-import#get_add'); + $admin_routes->post('/import/add')->to('admin-import#post_add'); + $admin_routes->get('/import/:set_id')->to('admin-import#list'); + $admin_routes->get('/import/:set_id/user')->to('admin-import#get_user'); + $admin_routes->get('/import/:set_id/org')->to('admin-import#get_org'); + + $admin_routes->get('/import/:set_id/ignore/:value_id') + ->to('admin-import#ignore_value'); + $admin_routes->get('/import/:set_id/import')->to('admin-import#run_import'); + + $admin_routes->get('/import_from')->to('admin-import_from#index'); + $admin_routes->post('/import_from/suppliers') + ->to('admin-import_from#post_suppliers'); + $admin_routes->post('/import_from/transactions') + ->to('admin-import_from#post_transactions'); + $admin_routes->post('/import_from/postcodes') + ->to('admin-import_from#post_postcodes'); + $admin_routes->get('/import_from/org_search') + ->to('admin-import_from#org_search'); + + # my $user_routes = $r->under('/')->to('root#under'); + + # $user_routes->get('/home')->to('root#home'); # my $portal_api = $r->under('/portal')->to('api-auth#check_json')->under('/')->to('portal#under'); -# $portal_api->post('/upload')->to('api-upload#post_upload'); -# $portal_api->post('/search')->to('api-upload#post_search'); - - $self->hook( before_dispatch => sub { - my $c = shift; - - $c->res->headers->header('Access-Control-Allow-Origin' => '*') if $c->app->mode eq 'development'; - }); - - $self->helper( copy_transactions_and_delete => sub { - my ( $c, $from_org, $to_org ) = @_; + # $portal_api->post('/upload')->to('api-upload#post_upload'); + # $portal_api->post('/search')->to('api-upload#post_search'); - my $from_org_transaction_rs = $from_org->transactions; + $self->hook( + before_dispatch => sub { + my $c = shift; - while ( my $from_org_transaction = $from_org_transaction_rs->next ) { - $to_org->create_related( - 'transactions', { - buyer_id => $from_org_transaction->buyer_id, - value => $from_org_transaction->value, - proof_image => $from_org_transaction->proof_image, - submitted_at => $from_org_transaction->submitted_at, - purchase_time => $from_org_transaction->purchase_time, + $c->res->headers->header( 'Access-Control-Allow-Origin' => '*' ) + if $c->app->mode eq 'development'; } - ); - $from_org_transaction->delete; - } - $from_org->delete; - }); + ); + + $self->helper( + copy_transactions_and_delete => sub { + my ( $c, $from_org, $to_org ) = @_; + + my $from_org_transaction_rs = $from_org->transactions; + + while ( my $from_org_transaction = $from_org_transaction_rs->next ) + { + $to_org->create_related( + 'transactions', + { + buyer_id => $from_org_transaction->buyer_id, + value => $from_org_transaction->value, + proof_image => $from_org_transaction->proof_image, + submitted_at => $from_org_transaction->submitted_at, + purchase_time => $from_org_transaction->purchase_time, + } + ); + $from_org_transaction->delete; + } + $from_org->delete; + } + ); + + return; } 1; diff --git a/lib/Pear/LocalLoop/Command/codepoint_open.pm b/lib/Pear/LocalLoop/Command/codepoint_open.pm index 5f286aa..9daee08 100644 --- a/lib/Pear/LocalLoop/Command/codepoint_open.pm +++ b/lib/Pear/LocalLoop/Command/codepoint_open.pm @@ -10,49 +10,51 @@ has description => 'Manage Codepoint Open Data'; has usage => sub { shift->extract_usage }; sub run { - my ( $self, @args ) = @_; - - getopt \@args, - 'o|outcodes=s' => \my @outcodes, - 'q|quiet' => \my $quiet_mode; - - my $cpo_dir = $self->app->home->child('etc')->child('code-point-open'); - my $zip_file = $cpo_dir->child('codepo_gb.zip')->realpath->to_string; - my $output_dir = $cpo_dir->child('codepo_gb')->realpath->to_string; - - unless ( -d $output_dir ) { - print "Unzipping code-point-open data\n" unless $quiet_mode; - eval { system( 'unzip', '-q', $zip_file, '-d', $output_dir ) }; - if ( my $err = $@ ) { - print "Error extracting zip: " . $err . "\n"; - print "Manually create etc/code-point-open/codepo_gb directory and extract zip into it"; - die; + my ( $self, @args ) = @_; + + getopt \@args, + 'o|outcodes=s' => \my @outcodes, + 'q|quiet' => \my $quiet_mode; + + my $cpo_dir = $self->app->home->child('etc')->child('code-point-open'); + my $zip_file = $cpo_dir->child('codepo_gb.zip')->realpath->to_string; + my $output_dir = $cpo_dir->child('codepo_gb')->realpath->to_string; + + unless ( -d $output_dir ) { + print "Unzipping code-point-open data\n" unless $quiet_mode; + eval { system( 'unzip', '-q', $zip_file, '-d', $output_dir ) }; + if ( my $err = $@ ) { + print "Error extracting zip: " . $err . "\n"; + print +"Manually create etc/code-point-open/codepo_gb directory and extract zip into it"; + die; + } } - } - - my $cpo = Geo::UK::Postcode::CodePointOpen->new( path => $output_dir ); - - printf( "Importing data for %s outcode(s)\n", @outcodes ? join( ' ', @outcodes ) : 'all' ) - unless $quiet_mode; - - my $iter = $cpo->read_iterator( - outcodes => \@outcodes, - include_lat_long => 1, - split_postcode => 1, - ); - - my $pc_rs = $self->app->schema->resultset('GbPostcode'); - while ( my $pc = $iter->() ) { - $pc_rs->find_or_create( - { - outcode => $pc->{Outcode}, - incode => $pc->{Incode}, - latitude => $pc->{Latitude}, - longitude => $pc->{Longitude}, - }, - { key => 'primary' }, + + my $cpo = Geo::UK::Postcode::CodePointOpen->new( path => $output_dir ); + + printf( "Importing data for %s outcode(s)\n", + @outcodes ? join( ' ', @outcodes ) : 'all' ) + unless $quiet_mode; + + my $iter = $cpo->read_iterator( + outcodes => \@outcodes, + include_lat_long => 1, + split_postcode => 1, ); - } + + my $pc_rs = $self->app->schema->resultset('GbPostcode'); + while ( my $pc = $iter->() ) { + $pc_rs->find_or_create( + { + outcode => $pc->{Outcode}, + incode => $pc->{Incode}, + latitude => $pc->{Latitude}, + longitude => $pc->{Longitude}, + }, + { key => 'primary' }, + ); + } } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Command/dev_data.pm b/lib/Pear/LocalLoop/Command/dev_data.pm index 5cf079b..611dcb5 100644 --- a/lib/Pear/LocalLoop/Command/dev_data.pm +++ b/lib/Pear/LocalLoop/Command/dev_data.pm @@ -8,79 +8,88 @@ has description => 'Input Dev Data'; has usage => sub { shift->extract_usage }; sub run { - my ( $self, @args ) = @_; - - getopt \@args, - 'f|force' => \my $force; - - unless ( defined $force ) { - say "Will not do anything without force option"; - return; - } - - if ( ( defined( $ENV{MOJO_MODE} ) && $ENV{MOJO_MODE} eq 'production' ) || $self->app->mode eq 'production' ) { - say "Will not run dev data fixtures in production!"; - return; - } - - my $schema = $self->app->schema; - - $schema->resultset('User')->create({ - email => 'test@example.com', - password => 'abc123', - entity => { - type => 'customer', - customer => { - full_name => 'Test User', - display_name => 'Test User', - year_of_birth => 2006, - postcode => 'LA1 1AA', - } - }, - is_admin => 1, - }); - - $schema->resultset('User')->create({ - email => 'test2@example.com', - password => 'abc123', - entity => { - type => 'customer', - customer => { - full_name => 'Test User 2', - display_name => 'Test User 2', - year_of_birth => 2006, - postcode => 'LA1 1AA', - }, - }, - }); - - $schema->resultset('User')->create({ - email => 'test3@example.com', - password => 'abc123', - entity => { - type => 'customer', - customer => { - full_name => 'Test User 3', - display_name => 'Test User 3', - year_of_birth => 2006, - postcode => 'LA1 1AA', - }, - }, - }); - - $schema->resultset('User')->create({ - email => 'testorg@example.com', - password => 'abc123', - entity => { - type => 'organisation', - organisation => { - name => 'Test Org', - street_name => 'Test Street', - town => 'Lancaster', - postcode => 'LA1 1AA', - }, - }, - }); + my ( $self, @args ) = @_; + + getopt \@args, 'f|force' => \my $force; + + unless ( defined $force ) { + say "Will not do anything without force option"; + return; + } + + if ( ( defined( $ENV{MOJO_MODE} ) && $ENV{MOJO_MODE} eq 'production' ) + || $self->app->mode eq 'production' ) + { + say "Will not run dev data fixtures in production!"; + return; + } + + my $schema = $self->app->schema; + + $schema->resultset('User')->create( + { + email => 'test@example.com', + password => 'abc123', + entity => { + type => 'customer', + customer => { + full_name => 'Test User', + display_name => 'Test User', + year_of_birth => 2006, + postcode => 'LA1 1AA', + } + }, + is_admin => 1, + } + ); + + $schema->resultset('User')->create( + { + email => 'test2@example.com', + password => 'abc123', + entity => { + type => 'customer', + customer => { + full_name => 'Test User 2', + display_name => 'Test User 2', + year_of_birth => 2006, + postcode => 'LA1 1AA', + }, + }, + } + ); + + $schema->resultset('User')->create( + { + email => 'test3@example.com', + password => 'abc123', + entity => { + type => 'customer', + customer => { + full_name => 'Test User 3', + display_name => 'Test User 3', + year_of_birth => 2006, + postcode => 'LA1 1AA', + }, + }, + } + ); + + $schema->resultset('User')->create( + { + email => 'testorg@example.com', + password => 'abc123', + entity => { + type => 'organisation', + organisation => { + name => 'Test Org', + street_name => 'Test Street', + town => 'Lancaster', + postcode => 'LA1 1AA', + }, + }, + } + ); } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Command/dev_transactions.pm b/lib/Pear/LocalLoop/Command/dev_transactions.pm index ec50fb1..2c491e0 100644 --- a/lib/Pear/LocalLoop/Command/dev_transactions.pm +++ b/lib/Pear/LocalLoop/Command/dev_transactions.pm @@ -1,4 +1,5 @@ package Pear::LocalLoop::Command::dev_transactions; + use Mojo::Base 'Mojolicious::Command'; use Mojo::Util 'getopt'; @@ -11,73 +12,84 @@ has description => 'Input Dev Transaction'; has usage => sub { shift->extract_usage }; sub run { - my ( $self, @args ) = @_; + my ( $self, @args ) = @_; - getopt \@args, - 'f|force' => \my $force, - 'd|date=s' => \my $date, - 'n|number=i' => \my $number, - 'c|count=i' => \my $count; + getopt \@args, + 'f|force' => \my $force, + 'd|date=s' => \my $date, + 'n|number=i' => \my $number, + 'c|count=i' => \my $count; - unless ( defined $force ) { - say "Will not do anything without force option"; - return; - } + unless ( defined $force ) { + say "Will not do anything without force option"; + return; + } - if ( ( defined( $ENV{MOJO_MODE} ) && $ENV{MOJO_MODE} eq 'production' ) || $self->app->mode eq 'production' ) { - say "Will not run dev data fixtures in production!"; - return; - } + if ( ( defined( $ENV{MOJO_MODE} ) && $ENV{MOJO_MODE} eq 'production' ) + || $self->app->mode eq 'production' ) + { + say "Will not run dev data fixtures in production!"; + return; + } - my $date_formatter = DateTime::Format::Strptime->new( - pattern => '%Y-%m-%d' - ); + my $date_formatter = + DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' ); - my $datetime; + my $datetime; - if ( defined $date ) { + if ( defined $date ) { - $datetime = $date_formatter->parse_datetime($date); + $datetime = $date_formatter->parse_datetime($date); - unless ( defined $datetime ) { - say "Unrecognised date format, please use 'YYYY-MM-DD' Format"; - return; + unless ( defined $datetime ) { + say "Unrecognised date format, please use 'YYYY-MM-DD' Format"; + return; + } + } + else { + $datetime = DateTime->today; } - } else { - $datetime = DateTime->today; - } - my $schema = $self->app->schema; + my $schema = $self->app->schema; - my $user_rs = $schema->resultset('User'); + my $user_rs = $schema->resultset('User'); - my $organisation_rs = $user_rs->search({ customer_id => undef }); + my $organisation_rs = $user_rs->search( { customer_id => undef } ); - my $dtf = $schema->storage->datetime_parser; + my $dtf = $schema->storage->datetime_parser; - my @organisations = $organisation_rs->all; + my @organisations = $organisation_rs->all; - unless ( defined $number ) { - $number = 1; - } + unless ( defined $number ) { + $number = 1; + } - unless ( defined $count ) { - $count = 0; - } + unless ( defined $count ) { + $count = 0; + } - for my $day_sub ( 0 .. $count ) { - $datetime->subtract( days => 1 ); - for ( 1 .. $number ) { - for my $user_result ( $user_rs->all ) { - $user_result->create_related( 'transactions', { - seller_id => $organisations[int(rand($#organisations))]->organisation_id, - value => int(rand(9999)) / 100, - proof_image => 'a', - purchase_time => $dtf->format_datetime($datetime->clone->add( minutes => int(rand(1440)) )), - }); - } + for my $day_sub ( 0 .. $count ) { + $datetime->subtract( days => 1 ); + for ( 1 .. $number ) { + for my $user_result ( $user_rs->all ) { + $user_result->create_related( + 'transactions', + { + seller_id => + $organisations[ int( rand($#organisations) ) ] + ->organisation_id, + value => int( rand(9999) ) / 100, + proof_image => 'a', + purchase_time => $dtf->format_datetime( + $datetime->clone->add( + minutes => int( rand(1440) ) + ) + ), + } + ); + } + } } - } } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Command/latlong_setup.pm b/lib/Pear/LocalLoop/Command/latlong_setup.pm index 1bf796a..4a3d649 100644 --- a/lib/Pear/LocalLoop/Command/latlong_setup.pm +++ b/lib/Pear/LocalLoop/Command/latlong_setup.pm @@ -11,63 +11,77 @@ has description => 'Set lat/long data on customers and orgs'; has usage => sub { shift->extract_usage }; sub run { - my ( $self, @args ) = @_; + my ( $self, @args ) = @_; - my $customer_rs = $self->app->schema->resultset('Customer'); - my $org_rs = $self->app->schema->resultset('Organisation'); + my $customer_rs = $self->app->schema->resultset('Customer'); + my $org_rs = $self->app->schema->resultset('Organisation'); - for my $result ( $customer_rs->all, $org_rs->all ) { - $self->_set_lat_long_for_result( $result ); - } + for my $result ( $customer_rs->all, $org_rs->all ) { + $self->_set_lat_long_for_result($result); + } - my $transaction_rs = $self->app->schema->resultset('Transaction'); + my $transaction_rs = $self->app->schema->resultset('Transaction'); - for my $result ( $transaction_rs->all ) { - my $distance = $self->_calculate_distance( - $result->buyer->${\$result->buyer->type}, - $result->seller->${\$result->seller->type}, - ); - $result->update({ distance => $distance }) if defined $distance; - } + for my $result ( $transaction_rs->all ) { + my $distance = $self->_calculate_distance( + $result->buyer->${ \$result->buyer->type }, + $result->seller->${ \$result->seller->type }, + ); + $result->update( { distance => $distance } ) if defined $distance; + } } sub _set_lat_long_for_result { - my ( $self, $result ) = @_; - - my $parsed_postcode = Geo::UK::Postcode::Regex->parse($result->postcode); - my $pc_rs = $self->app->schema->resultset('GbPostcode'); - - if ( $parsed_postcode->{valid} && !$parsed_postcode->{non_geographical} ) { - my $gb_pc = $pc_rs->find({ - outcode => $parsed_postcode->{outcode}, - incode => $parsed_postcode->{incode}, - }); - if ( $gb_pc ) { - $result->update({ - latitude => $gb_pc->latitude, - longitude => $gb_pc->longitude, - }); + my ( $self, $result ) = @_; + + my $parsed_postcode = Geo::UK::Postcode::Regex->parse( $result->postcode ); + my $pc_rs = $self->app->schema->resultset('GbPostcode'); + + if ( $parsed_postcode->{valid} && !$parsed_postcode->{non_geographical} ) { + my $gb_pc = $pc_rs->find( + { + outcode => $parsed_postcode->{outcode}, + incode => $parsed_postcode->{incode}, + } + ); + if ($gb_pc) { + $result->update( + { + latitude => $gb_pc->latitude, + longitude => $gb_pc->longitude, + } + ); + } } - } } sub _calculate_distance { - my ( $self, $buyer, $seller ) = @_; - - my $gis = GIS::Distance->new(); - - my $buyer_lat = $buyer->latitude; - my $buyer_long = $buyer->longitude; - my $seller_lat = $seller->latitude; - my $seller_long = $seller->longitude; - - if ( $buyer_lat && $buyer_long - && $seller_lat && $seller_long ) { - return $gis->distance( $buyer_lat, $buyer_long => $seller_lat, $seller_long )->meters; - } else { - print STDERR "missing lat-long for: " . $buyer->name . " or " . $seller->name . "\n"; - } - return; + my ( $self, $buyer, $seller ) = @_; + + my $gis = GIS::Distance->new(); + + my $buyer_lat = $buyer->latitude; + my $buyer_long = $buyer->longitude; + my $seller_lat = $seller->latitude; + my $seller_long = $seller->longitude; + + if ( $buyer_lat + && $buyer_long + && $seller_lat + && $seller_long ) + { + return $gis->distance( + $buyer_lat, + $buyer_long => $seller_lat, + $seller_long + )->meters; + } + else { + print STDERR "missing lat-long for: " + . $buyer->name . " or " + . $seller->name . "\n"; + } + return; } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Command/leaderboard.pm b/lib/Pear/LocalLoop/Command/leaderboard.pm index 5a62305..064b322 100644 --- a/lib/Pear/LocalLoop/Command/leaderboard.pm +++ b/lib/Pear/LocalLoop/Command/leaderboard.pm @@ -8,65 +8,69 @@ has description => 'Build leaderboards'; has usage => sub { shift->extract_usage }; sub run { - my ( $self, @args ) = @_; + my ( $self, @args ) = @_; - getopt \@args, - 't|type=s' => \my $type, - 'l|list' => \my $list, - 'd|date=s' => \my $date; + getopt \@args, + 't|type=s' => \my $type, + 'l|list' => \my $list, + 'd|date=s' => \my $date; - my $leaderboard_rs = $self->app->schema->resultset('Leaderboard'); + my $leaderboard_rs = $self->app->schema->resultset('Leaderboard'); - if ( defined $list ) { - say sprintf('%20s : %20s', 'Type', 'Name'); - for my $leaderboard ( $leaderboard_rs->all ) { - say sprintf('%20s : %20s', $leaderboard->type, $leaderboard->name); - } - return; - } - - if ( defined $type ) { - my $leaderboard = $leaderboard_rs->find({ type => $type }); - - unless ( defined $leaderboard ) { - say "Unknown Leaderboard Type"; - return; + if ( defined $list ) { + say sprintf( '%20s : %20s', 'Type', 'Name' ); + for my $leaderboard ( $leaderboard_rs->all ) { + say + sprintf( '%20s : %20s', $leaderboard->type, $leaderboard->name ); + } + return; } - if ( defined $date ) { - say "Creating leaderboard of type $type with date $date"; - - my $date_formatter = DateTime::Format::Strptime->new( - pattern => '%Y-%m-%d' - ); - - my $datetime = $date_formatter->parse_datetime($date); - - unless ( defined $datetime ) { - say "Unrecognised date format, please use 'YYYY-MM-DD' Format"; - return; - } - - my $dtf = $self->app->schema->storage->datetime_parser; - my $existing_leaderboard_set = $leaderboard->search_related( 'sets', { - date => $dtf->format_datetime( $datetime ), - })->first; - - if ( defined $existing_leaderboard_set ) { - $existing_leaderboard_set->values->delete_all; - $existing_leaderboard_set->delete; - } - - $leaderboard->create_new($datetime); - - say "Done"; - } else { - say 'Leaderboards of type ' . $type . ' available:'; - for my $set ( $leaderboard->sets->all ) { - say $set->date; - } + if ( defined $type ) { + my $leaderboard = $leaderboard_rs->find( { type => $type } ); + + unless ( defined $leaderboard ) { + say "Unknown Leaderboard Type"; + return; + } + + if ( defined $date ) { + say "Creating leaderboard of type $type with date $date"; + + my $date_formatter = + DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' ); + + my $datetime = $date_formatter->parse_datetime($date); + + unless ( defined $datetime ) { + say "Unrecognised date format, please use 'YYYY-MM-DD' Format"; + return; + } + + my $dtf = $self->app->schema->storage->datetime_parser; + my $existing_leaderboard_set = $leaderboard->search_related( + 'sets', + { + date => $dtf->format_datetime($datetime), + } + )->first; + + if ( defined $existing_leaderboard_set ) { + $existing_leaderboard_set->values->delete_all; + $existing_leaderboard_set->delete; + } + + $leaderboard->create_new($datetime); + + say "Done"; + } + else { + say 'Leaderboards of type ' . $type . ' available:'; + for my $set ( $leaderboard->sets->all ) { + say $set->date; + } + } } - } } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm b/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm index 2573f67..b04514e 100644 --- a/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm +++ b/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm @@ -8,11 +8,11 @@ has description => 'Build All leaderboards'; has usage => sub { shift->extract_usage }; sub run { - my ( $self, @args ) = @_; + my ( $self, @args ) = @_; - my $leaderboard_rs = $self->app->schema->resultset('Leaderboard'); + my $leaderboard_rs = $self->app->schema->resultset('Leaderboard'); - $leaderboard_rs->recalculate_all; + $leaderboard_rs->recalculate_all; } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Command/recur_transactions.pm b/lib/Pear/LocalLoop/Command/recur_transactions.pm index 7aab7ea..35fa032 100644 --- a/lib/Pear/LocalLoop/Command/recur_transactions.pm +++ b/lib/Pear/LocalLoop/Command/recur_transactions.pm @@ -11,119 +11,148 @@ has description => 'Recur Transactions'; has usage => sub { shift->extract_usage }; sub run { - my ( $self, @args ) = @_; + my ( $self, @args ) = @_; - my $app = $self->app; + my $app = $self->app; - getopt \@args, - 'f|force' => \my $force, - 'd|date=s' => \my $date; + getopt \@args, + 'f|force' => \my $force, + 'd|date=s' => \my $date; - unless ( defined $force ) { - say "Will not do anything without force option"; - return; - } + unless ( defined $force ) { + say "Will not do anything without force option"; + return; + } - my $date_formatter = DateTime::Format::Strptime->new( - pattern => '%Y-%m-%d' - ); + my $date_formatter = + DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' ); - my $datetime; + my $datetime; - if ( defined $date ) { + if ( defined $date ) { - $datetime = $date_formatter->parse_datetime($date); + $datetime = $date_formatter->parse_datetime($date); - unless ( defined $datetime ) { - say "Unrecognised date format, please use 'YYYY-MM-DD' Format"; - return; - } - } else { - $datetime = DateTime->today; - } - - my $match_date_day = $app->format_iso_date($datetime->clone->subtract( days => 1 )); - my $match_date_week = $app->format_iso_date($datetime->clone->subtract( weeks => 1 )); - my $match_date_fortnight = $app->format_iso_date($datetime->clone->subtract( weeks => 2 )); - my $match_date_month = $app->format_iso_date($datetime->clone->subtract( months => 1 )); - my $match_date_quarter = $app->format_iso_date($datetime->clone->subtract( months => 3)); - my $match_date_year = $app->format_iso_date($datetime->clone->subtract( years => 1 )); - - my $schema = $app->schema; - my $dtf = $schema->storage->datetime_parser; - my $recur_rs = $schema->resultset('TransactionRecurring'); - - for my $recur_result ( $recur_rs->all ) { - - my $start_time_dt; - if ( defined $recur_result->last_updated ) { - $start_time_dt = $recur_result->last_updated; - } else { - $start_time_dt = $recur_result->start_time; + unless ( defined $datetime ) { + say "Unrecognised date format, please use 'YYYY-MM-DD' Format"; + return; + } } - my $start_time = $app->format_iso_date($start_time_dt); - my $recurring_period = $recur_result->recurring_period; - - if ( $recurring_period eq 'daily' ) { - next unless $start_time eq $match_date_day; - say "matched recurring transaction ID " . $recur_result->id . " to daily"; - } elsif ( $recurring_period eq 'weekly' ) { - next unless $start_time eq $match_date_week; - say "matched recurring transaction ID " . $recur_result->id . " to weekly"; - } elsif ( $recurring_period eq 'fortnightly' ) { - next unless $start_time eq $match_date_fortnight; - say "matched recurring transaction ID " . $recur_result->id . " to fortnightly"; - } elsif ( $recurring_period eq 'monthly' ) { - next unless $start_time eq $match_date_month; - say "matched recurring transaction ID " . $recur_result->id . " to monthly"; - } elsif ( $recurring_period eq 'quarterly' ) { - next unless $start_time eq $match_date_quarter; - say "matched recurring transaction ID " . $recur_result->id . " to quarterly"; - } elsif ( $recurring_period eq 'yearly' ) { - next unless $start_time eq $match_date_year; - say "matched recurring transaction ID " . $recur_result->id . " to yearly"; - } else { - say "Invalid recurring time period given"; - return; + else { + $datetime = DateTime->today; } - my $purchase_time = DateTime->new( - year => $datetime->year, - month => $datetime->month, - day => $datetime->day, - hour => $start_time_dt->hour, - minute => $start_time_dt->minute, - second => $start_time_dt->second, - time_zone => 'UTC', - ); - my $category = $recur_result->category_id; - my $essential = $recur_result->essential; - my $distance = $recur_result->distance; - - my $new_transaction = $schema->resultset('Transaction')->create({ - buyer_id => $recur_result->buyer_id, - seller_id => $recur_result->seller_id, - value => $recur_result->value, - purchase_time => $app->format_db_datetime($purchase_time), - distance => $distance, - essential => ( defined $essential ? $essential : 0 ), - }); - - unless ( defined $new_transaction ) { - say "Error Adding Transaction"; - return; - } + my $match_date_day = + $app->format_iso_date( $datetime->clone->subtract( days => 1 ) ); + my $match_date_week = + $app->format_iso_date( $datetime->clone->subtract( weeks => 1 ) ); + my $match_date_fortnight = + $app->format_iso_date( $datetime->clone->subtract( weeks => 2 ) ); + my $match_date_month = + $app->format_iso_date( $datetime->clone->subtract( months => 1 ) ); + my $match_date_quarter = + $app->format_iso_date( $datetime->clone->subtract( months => 3 ) ); + my $match_date_year = + $app->format_iso_date( $datetime->clone->subtract( years => 1 ) ); + + my $schema = $app->schema; + my $dtf = $schema->storage->datetime_parser; + my $recur_rs = $schema->resultset('TransactionRecurring'); + + for my $recur_result ( $recur_rs->all ) { + + my $start_time_dt; + if ( defined $recur_result->last_updated ) { + $start_time_dt = $recur_result->last_updated; + } + else { + $start_time_dt = $recur_result->start_time; + } + my $start_time = $app->format_iso_date($start_time_dt); + my $recurring_period = $recur_result->recurring_period; + + if ( $recurring_period eq 'daily' ) { + next unless $start_time eq $match_date_day; + say "matched recurring transaction ID " + . $recur_result->id + . " to daily"; + } + elsif ( $recurring_period eq 'weekly' ) { + next unless $start_time eq $match_date_week; + say "matched recurring transaction ID " + . $recur_result->id + . " to weekly"; + } + elsif ( $recurring_period eq 'fortnightly' ) { + next unless $start_time eq $match_date_fortnight; + say "matched recurring transaction ID " + . $recur_result->id + . " to fortnightly"; + } + elsif ( $recurring_period eq 'monthly' ) { + next unless $start_time eq $match_date_month; + say "matched recurring transaction ID " + . $recur_result->id + . " to monthly"; + } + elsif ( $recurring_period eq 'quarterly' ) { + next unless $start_time eq $match_date_quarter; + say "matched recurring transaction ID " + . $recur_result->id + . " to quarterly"; + } + elsif ( $recurring_period eq 'yearly' ) { + next unless $start_time eq $match_date_year; + say "matched recurring transaction ID " + . $recur_result->id + . " to yearly"; + } + else { + say "Invalid recurring time period given"; + return; + } + + my $purchase_time = DateTime->new( + year => $datetime->year, + month => $datetime->month, + day => $datetime->day, + hour => $start_time_dt->hour, + minute => $start_time_dt->minute, + second => $start_time_dt->second, + time_zone => 'UTC', + ); + my $category = $recur_result->category_id; + my $essential = $recur_result->essential; + my $distance = $recur_result->distance; + + my $new_transaction = $schema->resultset('Transaction')->create( + { + buyer_id => $recur_result->buyer_id, + seller_id => $recur_result->seller_id, + value => $recur_result->value, + purchase_time => $app->format_db_datetime($purchase_time), + distance => $distance, + essential => ( defined $essential ? $essential : 0 ), + } + ); + + unless ( defined $new_transaction ) { + say "Error Adding Transaction"; + return; + } + + if ( defined $category ) { + $schema->resultset('TransactionCategory')->create( + { + category_id => $category, + transaction_id => $new_transaction->id, + } + ); + } + + $recur_result->update( { last_updated => $purchase_time } ); - if ( defined $category ) { - $schema->resultset('TransactionCategory')->create({ - category_id => $category, - transaction_id => $new_transaction->id, - }); } - - $recur_result->update({ last_updated => $purchase_time }); - - } } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Controller/Admin.pm b/lib/Pear/LocalLoop/Controller/Admin.pm index eee9253..13b2d73 100644 --- a/lib/Pear/LocalLoop/Controller/Admin.pm +++ b/lib/Pear/LocalLoop/Controller/Admin.pm @@ -2,57 +2,63 @@ package Pear::LocalLoop::Controller::Admin; use Mojo::Base 'Mojolicious::Controller'; sub under { - my $c = shift; + my $c = shift; - if ( $c->is_user_authenticated ) { - return 1 if $c->current_user->is_admin; - } - $c->redirect_to('/admin'); - return 0; + if ( $c->is_user_authenticated ) { + return 1 if $c->current_user->is_admin; + } + $c->redirect_to('/admin'); + return 0; } sub home { - my $c = shift; - - my $user_rs = $c->schema->resultset('User'); - my $token_rs = $c->schema->resultset('AccountToken'); - my $pending_orgs_rs = $c->schema->resultset('Organisation')->search({ pending => 1 }); - my $pending_transaction_rs = $pending_orgs_rs->entity->sales; - my $feedback_rs = $c->schema->resultset('Feedback'); - my $pending_feedback_rs = $feedback_rs->search({ actioned => 0 }); - $c->stash( - user_count => $user_rs->count, - tokens => { - total => $token_rs->count, - unused => $token_rs->search({ used => 0 })->count, - }, - pending_orgs => $pending_orgs_rs->count, - pending_trans => $pending_transaction_rs->count, - feedback => { - total => $feedback_rs->count, - pending => $pending_feedback_rs->count, - }, - ); + my $c = shift; + + my $user_rs = $c->schema->resultset('User'); + my $token_rs = $c->schema->resultset('AccountToken'); + my $pending_orgs_rs = + $c->schema->resultset('Organisation')->search( { pending => 1 } ); + my $pending_transaction_rs = $pending_orgs_rs->entity->sales; + my $feedback_rs = $c->schema->resultset('Feedback'); + my $pending_feedback_rs = $feedback_rs->search( { actioned => 0 } ); + $c->stash( + user_count => $user_rs->count, + tokens => { + total => $token_rs->count, + unused => $token_rs->search( { used => 0 } )->count, + }, + pending_orgs => $pending_orgs_rs->count, + pending_trans => $pending_transaction_rs->count, + feedback => { + total => $feedback_rs->count, + pending => $pending_feedback_rs->count, + }, + ); } sub auth_login { - my $c = shift; + my $c = shift; - $c->app->log->debug( __PACKAGE__ . " admin login attempt for [" . $c->param('email') . "]" ); + $c->app->log->debug( + __PACKAGE__ . " admin login attempt for [" . $c->param('email') . "]" ); - if ( $c->authenticate($c->param('email'), $c->param('password')) ) { - $c->redirect_to('/admin/home'); - } else { - $c->app->log->info( __PACKAGE__ . " failed admin login for [" . $c->param('email') . "]" ); - $c->redirect_to('/admin'); - } + if ( $c->authenticate( $c->param('email'), $c->param('password') ) ) { + $c->redirect_to('/admin/home'); + } + else { + $c->app->log->info( __PACKAGE__ + . " failed admin login for [" + . $c->param('email') + . "]" ); + $c->redirect_to('/admin'); + } } sub auth_logout { - my $c = shift; + my $c = shift; - $c->logout; - $c->redirect_to('/admin'); + $c->logout; + $c->redirect_to('/admin'); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Categories.pm b/lib/Pear/LocalLoop/Controller/Admin/Categories.pm index cb86d6e..6f89b3c 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Categories.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Categories.pm @@ -2,99 +2,116 @@ package Pear::LocalLoop::Controller::Admin::Categories; use Mojo::Base 'Mojolicious::Controller'; has result_set => sub { - my $c = shift; - return $c->schema->resultset('Category'); + my $c = shift; + return $c->schema->resultset('Category'); }; sub index { - my $c = shift; + my $c = shift; - my $category_rs = $c->result_set; - $category_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); - $c->stash( categories => [ $category_rs->all ] ); + my $category_rs = $c->result_set; + $category_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); + $c->stash( categories => [ $category_rs->all ] ); } # POST sub create { - my $c = shift; - - my $validation = $c->validation; - $validation->required('category', 'trim')->not_in_resultset('name', $c->result_set); - - my $category_name = $validation->param('category'); - - if ( $validation->has_error ) { - my $check = shift @{ $c->validation->error('category') }; - if ( $check eq 'required' ) { - $c->flash( error => 'Category name is required' ); - } elsif ( $check eq 'like' ) { - $c->flash( error => 'Category name not valid - Alphanumeric characters and Underscore only' ); - } elsif ( $check eq 'not_in_resultset' ) { - $c->flash( error => 'Category Already Exists' ); + my $c = shift; + + my $validation = $c->validation; + $validation->required( 'category', 'trim' ) + ->not_in_resultset( 'name', $c->result_set ); + + my $category_name = $validation->param('category'); + + if ( $validation->has_error ) { + my $check = shift @{ $c->validation->error('category') }; + if ( $check eq 'required' ) { + $c->flash( error => 'Category name is required' ); + } + elsif ( $check eq 'like' ) { + $c->flash( error => +'Category name not valid - Alphanumeric characters and Underscore only' + ); + } + elsif ( $check eq 'not_in_resultset' ) { + $c->flash( error => 'Category Already Exists' ); + } + } + else { + $c->flash( success => 'Category Created' ); + $c->result_set->create( { name => $category_name } ); } - } else { - $c->flash( success => 'Category Created' ); - $c->result_set->create({ name => $category_name }); - } - $c->redirect_to( '/admin/categories' ); + $c->redirect_to('/admin/categories'); } # GET sub read { - my $c = shift; + my $c = shift; - my $id = $c->param('id'); + my $id = $c->param('id'); - if ( my $category = $c->result_set->find($id) ) { - $c->stash( category => $category ); - } else { - $c->flash( error => 'No Category found' ); - $c->redirect_to( '/admin/categories' ); - } + if ( my $category = $c->result_set->find($id) ) { + $c->stash( category => $category ); + } + else { + $c->flash( error => 'No Category found' ); + $c->redirect_to('/admin/categories'); + } } # POST sub update { - my $c = shift; - my $validation = $c->validation; - $validation->required('id'); - $validation->required('category', 'trim')->like(qr/^[\w]*$/); - $validation->optional('line_icon'); - - my $id = $c->param('id'); - - if ( $validation->has_error ) { - my $names = $validation->failed; - $c->flash( error => 'Error in submitted data: ' . join(', ', @$names) ); - $c->redirect_to( '/admin/categories/' . $id ); - } elsif ( my $category = $c->result_set->find($id) ) { - $category->update({ - id => $validation->param('id'), - name => $validation->param('category'), - line_icon => (defined $validation->param('line_icon') ? $validation->param('line_icon') : undef ), - }); - $c->flash( success => 'Category Updated' ); - $c->redirect_to( '/admin/categories/' . $validation->param('id') ); - } else { - $c->flash( error => 'No Category found' ); - $c->redirect_to( '/admin/categories' ); - } + my $c = shift; + my $validation = $c->validation; + $validation->required('id'); + $validation->required( 'category', 'trim' )->like(qr/^[\w]*$/); + $validation->optional('line_icon'); + + my $id = $c->param('id'); + + if ( $validation->has_error ) { + my $names = $validation->failed; + $c->flash( + error => 'Error in submitted data: ' . join( ', ', @$names ) ); + $c->redirect_to( '/admin/categories/' . $id ); + } + elsif ( my $category = $c->result_set->find($id) ) { + $category->update( + { + id => $validation->param('id'), + name => $validation->param('category'), + line_icon => ( + defined $validation->param('line_icon') + ? $validation->param('line_icon') + : undef + ), + } + ); + $c->flash( success => 'Category Updated' ); + $c->redirect_to( '/admin/categories/' . $validation->param('id') ); + } + else { + $c->flash( error => 'No Category found' ); + $c->redirect_to('/admin/categories'); + } } # DELETE sub delete { - my $c = shift; - - my $id = $c->param('id'); - - if ( my $category = $c->result_set->find($id) ) { - $category->transaction_category->delete; - $category->delete; - $c->flash( success => 'Category Deleted' ); - } else { - $c->flash( error => 'No Category found' ); - } - $c->redirect_to( '/admin/categories' ); + my $c = shift; + + my $id = $c->param('id'); + + if ( my $category = $c->result_set->find($id) ) { + $category->transaction_category->delete; + $category->delete; + $c->flash( success => 'Category Deleted' ); + } + else { + $c->flash( error => 'No Category found' ); + } + $c->redirect_to('/admin/categories'); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm b/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm index a182362..9a7188b 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm @@ -2,50 +2,52 @@ package Pear::LocalLoop::Controller::Admin::Feedback; use Mojo::Base 'Mojolicious::Controller'; has result_set => sub { - my $c = shift; - return $c->schema->resultset('Feedback'); + my $c = shift; + return $c->schema->resultset('Feedback'); }; sub index { - my $c = shift; - - my $feedback_rs = $c->result_set->search( - undef, - { - page => $c->param('page') || 1, - rows => 12, - order_by => { -desc => 'submitted_at' }, - }, - ); - $c->stash( feedback_rs => $feedback_rs ); + my $c = shift; + + my $feedback_rs = $c->result_set->search( + undef, + { + page => $c->param('page') || 1, + rows => 12, + order_by => { -desc => 'submitted_at' }, + }, + ); + $c->stash( feedback_rs => $feedback_rs ); } sub read { - my $c = shift; + my $c = shift; - my $id = $c->param('id'); + my $id = $c->param('id'); - if ( my $feedback = $c->result_set->find($id) ) { - $c->stash( feedback => $feedback ); - } else { - $c->flash( error => 'No Feedback found' ); - $c->redirect_to( '/admin/feedback' ); - } + if ( my $feedback = $c->result_set->find($id) ) { + $c->stash( feedback => $feedback ); + } + else { + $c->flash( error => 'No Feedback found' ); + $c->redirect_to('/admin/feedback'); + } } sub actioned { - my $c = shift; - - my $id = $c->param('id'); - - if ( my $feedback = $c->result_set->find($id) ) { - $feedback->actioned( ! $feedback->actioned ); - $feedback->update; - $c->redirect_to( '/admin/feedback/' . $id ); - } else { - $c->flash( error => 'No Feedback found' ); - $c->redirect_to( '/admin/feedback' ); - } + my $c = shift; + + my $id = $c->param('id'); + + if ( my $feedback = $c->result_set->find($id) ) { + $feedback->actioned( !$feedback->actioned ); + $feedback->update; + $c->redirect_to( '/admin/feedback/' . $id ); + } + else { + $c->flash( error => 'No Feedback found' ); + $c->redirect_to('/admin/feedback'); + } } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Import.pm b/lib/Pear/LocalLoop/Controller/Admin/Import.pm index 630bf84..8ca2e8a 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Import.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Import.pm @@ -5,322 +5,352 @@ use Text::CSV; use Try::Tiny; has result_set => sub { - my $c = shift; - return $c->schema->resultset('ImportSet'); + my $c = shift; + return $c->schema->resultset('ImportSet'); }; sub index { - my $c = shift; + my $c = shift; - my $import_rs = $c->result_set->search( - undef, - { - page => $c->param('page') || 1, - rows => 10, - order_by => { -desc => 'date' }, - }, - ); - $c->stash( import_rs => $import_rs ); + my $import_rs = $c->result_set->search( + undef, + { + page => $c->param('page') || 1, + rows => 10, + order_by => { -desc => 'date' }, + }, + ); + $c->stash( import_rs => $import_rs ); } sub list { - my $c = shift; - my $set_id = $c->param('set_id'); - - my $include_ignored = $c->param('ignored'); - my $include_imported = $c->param('imported'); - - my $import_set = $c->result_set->find($set_id); - my $import_value_rs = $c->result_set->get_values($set_id, $include_ignored, $include_imported); - my $import_users_rs = $c->result_set->get_users($set_id, $include_ignored, $include_imported); - my $import_org_rs = $c->result_set->get_orgs($set_id, $include_ignored, $include_imported); - my $import_lookup_rs = $c->result_set->get_lookups($set_id); - - $c->stash( - import_set => $import_set, - import_value_rs => $import_value_rs, - import_users_rs => $import_users_rs, - import_org_rs => $import_org_rs, - import_lookup_rs => $import_lookup_rs, - ); + my $c = shift; + my $set_id = $c->param('set_id'); + + my $include_ignored = $c->param('ignored'); + my $include_imported = $c->param('imported'); + + my $import_set = $c->result_set->find($set_id); + my $import_value_rs = $c->result_set->get_values( $set_id, $include_ignored, + $include_imported ); + my $import_users_rs = + $c->result_set->get_users( $set_id, $include_ignored, $include_imported ); + my $import_org_rs = + $c->result_set->get_orgs( $set_id, $include_ignored, $include_imported ); + my $import_lookup_rs = $c->result_set->get_lookups($set_id); + + $c->stash( + import_set => $import_set, + import_value_rs => $import_value_rs, + import_users_rs => $import_users_rs, + import_org_rs => $import_org_rs, + import_lookup_rs => $import_lookup_rs, + ); } sub get_add { - my $c = shift; + my $c = shift; } sub post_add { - my $c = shift; - - my $csv_data = $c->param('csv'); - my $date_format = $c->param('date_format'); - - my $csv = Text::CSV->new({ - binary => 1, - allow_whitespace => 1, - }); - - open my $fh, '<', \$csv_data; - - # List context returns the actual headers - my @csv_headers; - my $error; - try { - @csv_headers = $csv->header( $fh ); - } catch { - $error = $_; - }; - - if ( defined $error ) { - $c->_csv_flash_error( $error ); - $c->redirect_to( '/admin/import/add' ); - return; - } - - # Text::CSV Already errors on duplicate columns, so this is fine - my @required = grep {/^user$|^value$|^date$|^organisation$/} @csv_headers; - - unless ( scalar( @required ) == 4 ) { - $c->_csv_flash_error( 'Required columns not available' ); - $c->redirect_to( '/admin/import/add' ); - return; - } - - my $csv_output = $csv->getline_hr_all( $fh ); - - unless ( scalar( @$csv_output ) ) { - $c->_csv_flash_error( "No data found" ); - $c->redirect_to( '/admin/import/add' ); - return; - } - - for my $data ( @$csv_output ) { - for my $key ( qw/ user value organisation / ) { - unless ( defined $data->{$key} ) { - $c->_csv_flash_error( "Undefined [$key] data found" ); - $c->redirect_to( '/admin/import/add' ); + my $c = shift; + + my $csv_data = $c->param('csv'); + my $date_format = $c->param('date_format'); + + my $csv = Text::CSV->new( + { + binary => 1, + allow_whitespace => 1, + } + ); + + open my $fh, '<', \$csv_data; + + # List context returns the actual headers + my @csv_headers; + my $error; + try { + @csv_headers = $csv->header($fh); + } + catch { + $error = $_; + }; + + if ( defined $error ) { + $c->_csv_flash_error($error); + $c->redirect_to('/admin/import/add'); + return; + } + + # Text::CSV Already errors on duplicate columns, so this is fine + my @required = grep { /^user$|^value$|^date$|^organisation$/ } @csv_headers; + + unless ( scalar(@required) == 4 ) { + $c->_csv_flash_error('Required columns not available'); + $c->redirect_to('/admin/import/add'); return; - } } - if ( defined $data->{date} ) { - my $dtp = DateTime::Format::Strptime->new( pattern => $date_format ); - my $dt_obj = $dtp->parse_datetime($data->{date}); - unless ( defined $dt_obj ) { - $c->_csv_flash_error( "Undefined or incorrect format for [date] data found" ); - $c->redirect_to( '/admin/import/add' ); + + my $csv_output = $csv->getline_hr_all($fh); + + unless ( scalar(@$csv_output) ) { + $c->_csv_flash_error("No data found"); + $c->redirect_to('/admin/import/add'); return; - } - $data->{date} = $dt_obj; } - } - - my $value_set; - $c->schema->txn_do( - sub { - $value_set = $c->result_set->create({}); - - $value_set->values->populate( - [ - [ qw/ user_name purchase_value purchase_date org_name / ], - ( map { [ @{$_}{qw/ user value date organisation /} ] } @$csv_output ), - ] - ); + + for my $data (@$csv_output) { + for my $key (qw/ user value organisation /) { + unless ( defined $data->{$key} ) { + $c->_csv_flash_error("Undefined [$key] data found"); + $c->redirect_to('/admin/import/add'); + return; + } + } + if ( defined $data->{date} ) { + my $dtp = + DateTime::Format::Strptime->new( pattern => $date_format ); + my $dt_obj = $dtp->parse_datetime( $data->{date} ); + unless ( defined $dt_obj ) { + $c->_csv_flash_error( + "Undefined or incorrect format for [date] data found"); + $c->redirect_to('/admin/import/add'); + return; + } + $data->{date} = $dt_obj; + } } - ); - unless ( defined $value_set ) { - $c->_csv_flash_error( 'Error creating new Value Set' ); - $c->redirect_to( '/admin/import/add' ); - return; - } + my $value_set; + $c->schema->txn_do( + sub { + $value_set = $c->result_set->create( {} ); + + $value_set->values->populate( + [ + [qw/ user_name purchase_value purchase_date org_name /], + ( + map { [ @{$_}{qw/ user value date organisation /} ] } + @$csv_output + ), + ] + ); + } + ); - $c->flash( success => 'Created Value Set' ); - $c->redirect_to( '/admin/import/' . $value_set->id ); + unless ( defined $value_set ) { + $c->_csv_flash_error('Error creating new Value Set'); + $c->redirect_to('/admin/import/add'); + return; + } + + $c->flash( success => 'Created Value Set' ); + $c->redirect_to( '/admin/import/' . $value_set->id ); } sub _csv_flash_error { - my ( $c, $error ) = @_; - $error //= "An error occurred"; - - $c->flash( - error => $error, - # If csv info is huge, this fails epically - #csv_data => $c->param('csv'), - date_format => $c->param('date_format'), - ); + my ( $c, $error ) = @_; + $error //= "An error occurred"; + + $c->flash( + error => $error, + + # If csv info is huge, this fails epically + #csv_data => $c->param('csv'), + date_format => $c->param('date_format'), + ); } sub get_user { - my $c = shift; - my $set_id = $c->param('set_id'); - my $user_name = $c->param('user'); + my $c = shift; + my $set_id = $c->param('set_id'); + my $user_name = $c->param('user'); - my $values_rs = $c->result_set->find($set_id)->values->search( - { - user_name => $user_name, - ignore_value => 0, - } - ); + my $values_rs = $c->result_set->find($set_id)->values->search( + { + user_name => $user_name, + ignore_value => 0, + } + ); - unless ( $values_rs->count > 0 ) { - $c->flash( error => 'User not found or all values are ignored' ); - return $c->redirect_to( '/admin/import/' . $set_id ); - } + unless ( $values_rs->count > 0 ) { + $c->flash( error => 'User not found or all values are ignored' ); + return $c->redirect_to( '/admin/import/' . $set_id ); + } - my $lookup_result = $c->result_set->find($set_id)->lookups->find( - { name => $user_name }, - ); + my $lookup_result = + $c->result_set->find($set_id)->lookups->find( { name => $user_name }, ); - my $entity_id = $c->param('entity'); + my $entity_id = $c->param('entity'); - my $users_rs = $c->schema->resultset('User'); + my $users_rs = $c->schema->resultset('User'); - if ( defined $entity_id && $users_rs->find({ entity_id => $entity_id }) ) { - if ( defined $lookup_result ) { - $lookup_result->update({ entity_id => $entity_id }); - } else { - $lookup_result = $c->result_set->find($set_id)->lookups->create( - { - name => $user_name, - entity_id => $entity_id, - }, - ); + if ( defined $entity_id && $users_rs->find( { entity_id => $entity_id } ) ) + { + if ( defined $lookup_result ) { + $lookup_result->update( { entity_id => $entity_id } ); + } + else { + $lookup_result = $c->result_set->find($set_id)->lookups->create( + { + name => $user_name, + entity_id => $entity_id, + }, + ); + } } - } elsif ( defined $entity_id ) { - $c->stash( error => "User does not exist" ); - } - - $c->stash( - users_rs => $users_rs, - lookup => $lookup_result, - user_name => $user_name, - ); + elsif ( defined $entity_id ) { + $c->stash( error => "User does not exist" ); + } + + $c->stash( + users_rs => $users_rs, + lookup => $lookup_result, + user_name => $user_name, + ); } sub get_org { - my $c = shift; - my $set_id = $c->param('set_id'); - my $org_name = $c->param('org'); + my $c = shift; + my $set_id = $c->param('set_id'); + my $org_name = $c->param('org'); - my $values_rs = $c->result_set->find($set_id)->values->search( - { - org_name => $org_name, - ignore_value => 0, - } - ); + my $values_rs = $c->result_set->find($set_id)->values->search( + { + org_name => $org_name, + ignore_value => 0, + } + ); - unless ( $values_rs->count > 0 ) { - $c->flash( error => 'Organisation not found or all values are ignored' ); - return $c->redirect_to( '/admin/import/' . $set_id ); - } + unless ( $values_rs->count > 0 ) { + $c->flash( + error => 'Organisation not found or all values are ignored' ); + return $c->redirect_to( '/admin/import/' . $set_id ); + } - my $lookup_result = $c->result_set->find($set_id)->lookups->find( - { name => $org_name }, - ); + my $lookup_result = + $c->result_set->find($set_id)->lookups->find( { name => $org_name }, ); - my $entity_id = $c->param('entity'); + my $entity_id = $c->param('entity'); - my $orgs_rs = $c->schema->resultset('Organisation'); + my $orgs_rs = $c->schema->resultset('Organisation'); - if ( defined $entity_id && $orgs_rs->find({ entity_id => $entity_id }) ) { - if ( defined $lookup_result ) { - $lookup_result->update({ entity_id => $entity_id }); - } else { - $lookup_result = $c->result_set->find($set_id)->lookups->create( - { - name => $org_name, - entity_id => $entity_id, - }, - ); + if ( defined $entity_id && $orgs_rs->find( { entity_id => $entity_id } ) ) { + if ( defined $lookup_result ) { + $lookup_result->update( { entity_id => $entity_id } ); + } + else { + $lookup_result = $c->result_set->find($set_id)->lookups->create( + { + name => $org_name, + entity_id => $entity_id, + }, + ); + } } - } elsif ( defined $entity_id ) { - $c->stash( error => "Organisation does not exist" ); - } - - $c->stash( - orgs_rs => $orgs_rs, - lookup => $lookup_result, - org_name => $org_name, - ); + elsif ( defined $entity_id ) { + $c->stash( error => "Organisation does not exist" ); + } + + $c->stash( + orgs_rs => $orgs_rs, + lookup => $lookup_result, + org_name => $org_name, + ); } sub ignore_value { - my $c = shift; - my $set_id = $c->param('set_id'); - my $value_id = $c->param('value_id'); - - my $set_result = $c->result_set->find($set_id); - unless ( defined $set_result ) { - $c->flash( error => "Set does not exist" ); - return $c->redirect_to( '/admin/import' ); - } - - my $value_result = $set_result->values->find($value_id); - unless ( defined $value_result ) { - $c->flash( error => "Value does not exist" ); - return $c->redirect_to( '/admin/import/' . $set_id ); - } - - $value_result->update({ ignore_value => $value_result->ignore_value ? 0 : 1 }); - - $c->flash( success => "Updated value" ); - my $referer = $c->req->headers->header('Referer'); - return $c->redirect_to( - defined $referer - ? $c->url_for($referer)->path_query - : '/admin/import/' . $set_id - ); + my $c = shift; + my $set_id = $c->param('set_id'); + my $value_id = $c->param('value_id'); + + my $set_result = $c->result_set->find($set_id); + unless ( defined $set_result ) { + $c->flash( error => "Set does not exist" ); + return $c->redirect_to('/admin/import'); + } + + my $value_result = $set_result->values->find($value_id); + unless ( defined $value_result ) { + $c->flash( error => "Value does not exist" ); + return $c->redirect_to( '/admin/import/' . $set_id ); + } + + $value_result->update( + { ignore_value => $value_result->ignore_value ? 0 : 1 } ); + + $c->flash( success => "Updated value" ); + my $referer = $c->req->headers->header('Referer'); + return $c->redirect_to( + defined $referer + ? $c->url_for($referer)->path_query + : '/admin/import/' . $set_id + ); } sub run_import { - my $c = shift; - my $set_id = $c->param('set_id'); - - my $set_result = $c->result_set->find($set_id); - unless ( defined $set_result ) { - $c->flash( error => "Set does not exist" ); - return $c->redirect_to( '/admin/import' ); - } - - my $import_value_rs = $c->result_set->get_values($set_id, undef, undef); - my $import_lookup = $c->result_set->get_lookups($set_id); - my $entity_rs = $c->schema->resultset('Entity'); - - $c->schema->txn_do( - sub { - for my $value_result ( $import_value_rs->all ) { - my $user_lookup = $import_lookup->{ $value_result->user_name }; - my $org_lookup = $import_lookup->{ $value_result->org_name }; - my $value_lookup = $c->parse_currency( $value_result->purchase_value ); - - if ( defined $user_lookup && defined $org_lookup && $value_lookup ) { - my $user_entity = $entity_rs->find($user_lookup->{entity_id}); - my $org_entity = $entity_rs->find($org_lookup->{entity_id}); - my $distance = $c->get_distance_from_coords( $user_entity->type_object, $org_entity->type_object ); - my $transaction = $c->schema->resultset('Transaction')->create( - { - buyer => $user_entity, - seller => $org_entity, - value => $value_lookup * 100000, - purchase_time => $value_result->purchase_date, - distance => $distance, + my $c = shift; + my $set_id = $c->param('set_id'); + + my $set_result = $c->result_set->find($set_id); + unless ( defined $set_result ) { + $c->flash( error => "Set does not exist" ); + return $c->redirect_to('/admin/import'); + } + + my $import_value_rs = $c->result_set->get_values( $set_id, undef, undef ); + my $import_lookup = $c->result_set->get_lookups($set_id); + my $entity_rs = $c->schema->resultset('Entity'); + + $c->schema->txn_do( + sub { + for my $value_result ( $import_value_rs->all ) { + my $user_lookup = $import_lookup->{ $value_result->user_name }; + my $org_lookup = $import_lookup->{ $value_result->org_name }; + my $value_lookup = + $c->parse_currency( $value_result->purchase_value ); + + if ( defined $user_lookup + && defined $org_lookup + && $value_lookup ) + { + my $user_entity = + $entity_rs->find( $user_lookup->{entity_id} ); + my $org_entity = + $entity_rs->find( $org_lookup->{entity_id} ); + my $distance = + $c->get_distance_from_coords( $user_entity->type_object, + $org_entity->type_object ); + my $transaction = + $c->schema->resultset('Transaction')->create( + { + buyer => $user_entity, + seller => $org_entity, + value => $value_lookup * 100000, + purchase_time => $value_result->purchase_date, + distance => $distance, + } + ); + $value_result->update( + { transaction_id => $transaction->id } ); + } + else { + $c->app->log->warn( "Failed value import for value id [" + . $value_result->id + . "], ignoring" ); + } } - ); - $value_result->update({transaction_id => $transaction->id }); - } else { - $c->app->log->warn("Failed value import for value id [" . $value_result->id . "], ignoring"); } - } - } - ); - - $c->flash( success => "Import completed for ready values" ); - my $referer = $c->req->headers->header('Referer'); - return $c->redirect_to( - defined $referer - ? $c->url_for($referer)->path_query - : '/admin/import/' . $set_id - ); + ); + + $c->flash( success => "Import completed for ready values" ); + my $referer = $c->req->headers->header('Referer'); + return $c->redirect_to( + defined $referer + ? $c->url_for($referer)->path_query + : '/admin/import/' . $set_id + ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm b/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm index 78cc590..72ce999 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm @@ -5,123 +5,131 @@ use Try::Tiny; use Mojo::File qw/path/; sub index { - my $c = shift; - $c->stash->{org_entities} = [ - map { - { id => $_->entity_id, name => $_->name } - } $c->schema->resultset('Organisation')->search({ name => { like => '%lancashire%' }}, { columns => [qw/ entity_id name / ]}) - ]; - - $c->app->max_request_size(104857600); + my $c = shift; + $c->stash->{org_entities} = [ + map { { id => $_->entity_id, name => $_->name } } + $c->schema->resultset('Organisation')->search( + { name => { like => '%lancashire%' } }, + { columns => [qw/ entity_id name /] } + ) + ]; + + $c->app->max_request_size(104857600); } sub post_suppliers { - my $c = shift; + my $c = shift; - unless ($c->param('suppliers_csv')) { - $c->flash(error => "No CSV file given"); - return $c->redirect_to('/admin/import_from'); - } + unless ( $c->param('suppliers_csv') ) { + $c->flash( error => "No CSV file given" ); + return $c->redirect_to('/admin/import_from'); + } - # Check file size - if ($c->req->is_limit_exceeded) { - $c->flash(error => "CSV file size is too large"); - return $c->redirect_to('/admin/import_from'); - } + # Check file size + if ( $c->req->is_limit_exceeded ) { + $c->flash( error => "CSV file size is too large" ); + return $c->redirect_to('/admin/import_from'); + } - my $file = $c->param('suppliers_csv'); + my $file = $c->param('suppliers_csv'); - my $filename = path($c->app->config->{upload_path}, time . 'suppliers.csv'); + my $filename = + path( $c->app->config->{upload_path}, time . 'suppliers.csv' ); - $file->move_to($filename); + $file->move_to($filename); - my $job_id = $c->minion->enqueue('csv_supplier_import' => [ $filename ]); + my $job_id = $c->minion->enqueue( 'csv_supplier_import' => [$filename] ); - my $job_url = $c->url_for("/admin/minion/jobs?id=$job_id")->to_abs; + my $job_url = $c->url_for("/admin/minion/jobs?id=$job_id")->to_abs; - $c->flash(success => "CSV import started, see status of minion job at: $job_url"); - return $c->redirect_to('/admin/import_from'); + $c->flash( success => + "CSV import started, see status of minion job at: $job_url" ); + return $c->redirect_to('/admin/import_from'); } sub post_postcodes { - my $c = shift; + my $c = shift; - unless ($c->param('postcodes_csv')) { - $c->flash(error => "No CSV file given"); - return $c->redirect_to('/admin/import_from'); - } + unless ( $c->param('postcodes_csv') ) { + $c->flash( error => "No CSV file given" ); + return $c->redirect_to('/admin/import_from'); + } - # Check file size - if ($c->req->is_limit_exceeded) { - $c->flash(error => "CSV file size is too large"); - return $c->redirect_to('/admin/import_from'); - } + # Check file size + if ( $c->req->is_limit_exceeded ) { + $c->flash( error => "CSV file size is too large" ); + return $c->redirect_to('/admin/import_from'); + } - my $file = $c->param('postcodes_csv'); + my $file = $c->param('postcodes_csv'); - my $filename = path($c->app->config->{upload_path}, time . 'postcodes.csv'); + my $filename = + path( $c->app->config->{upload_path}, time . 'postcodes.csv' ); - $file->move_to($filename); + $file->move_to($filename); - my $job_id = $c->minion->enqueue('csv_postcode_import' => [ $filename ]); + my $job_id = $c->minion->enqueue( 'csv_postcode_import' => [$filename] ); - my $job_url = $c->url_for("/admin/minion/jobs?id=$job_id")->to_abs; + my $job_url = $c->url_for("/admin/minion/jobs?id=$job_id")->to_abs; - $c->flash(success => "CSV import started, see status of minion job at: $job_url"); - return $c->redirect_to('/admin/import_from'); + $c->flash( success => + "CSV import started, see status of minion job at: $job_url" ); + return $c->redirect_to('/admin/import_from'); } sub post_transactions { - my $c = shift; + my $c = shift; - unless ($c->param('entity_id') ne '') { - $c->flash(error => "Please Choose an organisation"); - return $c->redirect_to('/admin/import_from'); - } + unless ( $c->param('entity_id') ne '' ) { + $c->flash( error => "Please Choose an organisation" ); + return $c->redirect_to('/admin/import_from'); + } - unless ($c->param('transactions_csv')) { - $c->flash(error => "No CSV file given"); - return $c->redirect_to('/admin/import_from'); - } + unless ( $c->param('transactions_csv') ) { + $c->flash( error => "No CSV file given" ); + return $c->redirect_to('/admin/import_from'); + } - # Check file size - if ($c->req->is_limit_exceeded) { - $c->flash(error => "CSV file size is too large"); - return $c->redirect_to('/admin/import_from'); - } + # Check file size + if ( $c->req->is_limit_exceeded ) { + $c->flash( error => "CSV file size is too large" ); + return $c->redirect_to('/admin/import_from'); + } - my $file = $c->param('transactions_csv'); + my $file = $c->param('transactions_csv'); - my $filename = path($c->app->config->{upload_path}, time . 'transactions.csv'); + my $filename = + path( $c->app->config->{upload_path}, time . 'transactions.csv' ); - $file->move_to($filename); + $file->move_to($filename); - my $job_id = $c->minion->enqueue('csv_transaction_import' => [ $filename, $c->param('entity_id') ]); + my $job_id = $c->minion->enqueue( + 'csv_transaction_import' => [ $filename, $c->param('entity_id') ] ); - my $job_url = $c->url_for("/admin/minion/jobs?id=$job_id")->to_abs; + my $job_url = $c->url_for("/admin/minion/jobs?id=$job_id")->to_abs; - $c->flash(success => "CSV import started, see status of minion job at: $job_url"); - return $c->redirect_to('/admin/import_from'); + $c->flash( success => + "CSV import started, see status of minion job at: $job_url" ); + return $c->redirect_to('/admin/import_from'); } sub org_search { - my $c = shift; - my $term = $c->param('term'); - - my $rs = $c->schema->resultset('Organisation')->search( - { name => { like => $term . '%' } }, - { - join => 'entity', - columns => [ qw/ me.name entity.id / ] - }, - ); - - my @results = ( map { { - label => $_->name, - value => $_->entity->id, - } } $rs->all); - - $c->render( json => \@results ); + my $c = shift; + my $term = $c->param('term'); + + my $rs = $c->schema->resultset('Organisation')->search( + { name => { like => $term . '%' } }, + { + join => 'entity', + columns => [qw/ me.name entity.id /] + }, + ); + + my @results = ( + map { { label => $_->name, value => $_->entity->id, } } $rs->all + ); + + $c->render( json => \@results ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index ad45129..ef85636 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -4,261 +4,297 @@ use Mojo::Base 'Mojolicious::Controller'; use Try::Tiny; has result_set => sub { - my $c = shift; - return $c->schema->resultset('Organisation'); + my $c = shift; + return $c->schema->resultset('Organisation'); }; sub list { - my $c = shift; - - my $orgs_rs = $c->schema->resultset('Organisation')->search( - undef, - { - page => $c->param('page') || 1, - rows => 10, - order_by => { -asc => 'name' }, - }, - ); - - $c->stash( - orgs_rs => $orgs_rs, - ); + my $c = shift; + + my $orgs_rs = $c->schema->resultset('Organisation')->search( + undef, + { + page => $c->param('page') || 1, + rows => 10, + order_by => { -asc => 'name' }, + }, + ); + + $c->stash( orgs_rs => $orgs_rs, ); } sub add_org { - my $c = shift; + my $c = shift; } sub add_org_submit { - my $c = shift; - - my $validation = $c->validation; - - $validation->required('name'); - $validation->optional('street_name'); - $validation->required('town'); - $validation->optional('sector'); - $validation->optional('postcode')->postcode; - $validation->optional('pending'); - $validation->optional('is_local'); - $validation->optional('is_fair'); - - if ( $validation->has_error ) { - $c->flash( error => 'The validation has failed' ); - return $c->redirect_to( '/admin/organisations/add' ); - } - - my $organisation; - - my $location = $c->get_location_from_postcode( - $validation->param('postcode'), - 'organisation', - ); - - try { - my $entity = $c->schema->resultset('Entity')->create({ - organisation => { - name => $validation->param('name'), - street_name => $validation->param('street_name'), - town => $validation->param('town'), - sector => $validation->param('sector'), - postcode => $validation->param('postcode'), - ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), - submitted_by_id => $c->current_user->id, - pending => defined $validation->param('pending') ? 0 : 1, - is_local => $validation->param('is_local'), - is_fair => $validation->param('is_fair'), - }, - type => 'organisation', - }); - $organisation = $entity->organisation; - } finally { - if ( @_ ) { - $c->flash( error => 'Something went wrong Adding the Organisation' ); - $c->redirect_to( '/admin/organisations/add' ); - } else { - $c->flash( success => 'Added Organisation' ); - $c->redirect_to( '/admin/organisations/' . $organisation->id); + my $c = shift; + + my $validation = $c->validation; + + $validation->required('name'); + $validation->optional('street_name'); + $validation->required('town'); + $validation->optional('sector'); + $validation->optional('postcode')->postcode; + $validation->optional('pending'); + $validation->optional('is_local'); + $validation->optional('is_fair'); + + if ( $validation->has_error ) { + $c->flash( error => 'The validation has failed' ); + return $c->redirect_to('/admin/organisations/add'); } - }; + + my $organisation; + + my $location = + $c->get_location_from_postcode( $validation->param('postcode'), + 'organisation', ); + + try { + my $entity = $c->schema->resultset('Entity')->create( + { + organisation => { + name => $validation->param('name'), + street_name => $validation->param('street_name'), + town => $validation->param('town'), + sector => $validation->param('sector'), + postcode => $validation->param('postcode'), + ( + defined $location + ? (%$location) + : ( latitude => undef, longitude => undef ) + ), + submitted_by_id => $c->current_user->id, + pending => defined $validation->param('pending') ? 0 : 1, + is_local => $validation->param('is_local'), + is_fair => $validation->param('is_fair'), + }, + type => 'organisation', + } + ); + $organisation = $entity->organisation; + } + finally { + if (@_) { + $c->flash( + error => 'Something went wrong Adding the Organisation' ); + $c->redirect_to('/admin/organisations/add'); + } + else { + $c->flash( success => 'Added Organisation' ); + $c->redirect_to( '/admin/organisations/' . $organisation->id ); + } + }; } sub valid_read { - my $c = shift; - my $valid_org = $c->schema->resultset('Organisation')->find( $c->param('id') ); - my $transactions = $valid_org->entity->purchases->search( - undef, { - page => $c->param('page') || 1, - rows => 10, - order_by => { -desc => 'submitted_at' }, - }, - ); - my $associations = $valid_org->entity->associations; - my $assoc = { - lis => defined $associations ? $associations->lis : 0, - esta => defined $associations ? $associations->esta : 0, - }; - - $c->stash( - valid_org => $valid_org, - transactions => $transactions, - associations => $assoc, - ); + my $c = shift; + my $valid_org = + $c->schema->resultset('Organisation')->find( $c->param('id') ); + my $transactions = $valid_org->entity->purchases->search( + undef, + { + page => $c->param('page') || 1, + rows => 10, + order_by => { -desc => 'submitted_at' }, + }, + ); + my $associations = $valid_org->entity->associations; + my $assoc = { + lis => defined $associations ? $associations->lis : 0, + esta => defined $associations ? $associations->esta : 0, + }; + + $c->stash( + valid_org => $valid_org, + transactions => $transactions, + associations => $assoc, + ); } sub valid_edit { - my $c = shift; - - my $validation = $c->validation; - $validation->required('name'); - $validation->optional('street_name'); - $validation->required('town'); - $validation->optional('sector'); - $validation->required('postcode')->postcode; - $validation->optional('pending'); - $validation->optional('is_local'); - $validation->optional('is_fair'); - $validation->optional('is_lis'); - $validation->optional('is_esta'); - - if ( $validation->has_error ) { - $c->flash( error => 'The validation has failed' ); - return $c->redirect_to( '/admin/organisations/' . $c->param('id') ); - } - - my $valid_org = $c->schema->resultset('Organisation')->find( $c->param('id') ); - - my $location = $c->get_location_from_postcode( - $validation->param('postcode'), - 'organisation', - ); - - try { - $c->schema->storage->txn_do( sub { - $valid_org->update({ - name => $validation->param('name'), - street_name => $validation->param('street_name'), - town => $validation->param('town'), - sector => $validation->param('sector'), - postcode => $validation->param('postcode'), - ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), - pending => defined $validation->param('pending') ? 0 : 1, - is_local => $validation->param('is_local'), - is_fair => $validation->param('is_fair'), - }); - $valid_org->entity->update_or_create_related( 'associations', { - lis => $validation->param('is_lis'), - esta => $validation->param('is_esta') - }); - } ); - } finally { - if ( @_ ) {use Devel::Dwarn; Dwarn \@_; - $c->flash( error => 'Something went wrong Updating the Organisation' ); - } else { - $c->flash( success => 'Updated Organisation' ); + my $c = shift; + + my $validation = $c->validation; + $validation->required('name'); + $validation->optional('street_name'); + $validation->required('town'); + $validation->optional('sector'); + $validation->required('postcode')->postcode; + $validation->optional('pending'); + $validation->optional('is_local'); + $validation->optional('is_fair'); + $validation->optional('is_lis'); + $validation->optional('is_esta'); + + if ( $validation->has_error ) { + $c->flash( error => 'The validation has failed' ); + return $c->redirect_to( '/admin/organisations/' . $c->param('id') ); } - }; - $c->redirect_to( '/admin/organisations/' . $c->param('id') ); + + my $valid_org = + $c->schema->resultset('Organisation')->find( $c->param('id') ); + + my $location = + $c->get_location_from_postcode( $validation->param('postcode'), + 'organisation', ); + + try { + $c->schema->storage->txn_do( + sub { + $valid_org->update( + { + name => $validation->param('name'), + street_name => $validation->param('street_name'), + town => $validation->param('town'), + sector => $validation->param('sector'), + postcode => $validation->param('postcode'), + ( + defined $location ? (%$location) + : ( latitude => undef, longitude => undef ) + ), + pending => defined $validation->param('pending') ? 0 + : 1, + is_local => $validation->param('is_local'), + is_fair => $validation->param('is_fair'), + } + ); + $valid_org->entity->update_or_create_related( + 'associations', + { + lis => $validation->param('is_lis'), + esta => $validation->param('is_esta') + } + ); + } + ); + } + finally { + if (@_) { + use Devel::Dwarn; + Dwarn \@_; + $c->flash( + error => 'Something went wrong Updating the Organisation' ); + } + else { + $c->flash( success => 'Updated Organisation' ); + } + }; + $c->redirect_to( '/admin/organisations/' . $c->param('id') ); } sub merge_list { - my $c = shift; + my $c = shift; - my $org_id = $c->param('id'); - my $org_result = $c->result_set->find($org_id); + my $org_id = $c->param('id'); + my $org_result = $c->result_set->find($org_id); - if ( defined $org_result->entity->user ) { - $c->flash( error => 'Cannot merge from user-owned organisation!' ); - $c->redirect_to( '/admin/organisations/' . $org_id ); - return; - } - - my $org_rs = $c->result_set->search( - { - id => { '!=' => $org_id }, - }, - { - page => $c->param('page') || 1, - rows => 10, - order_by => { '-asc' => 'name' }, + if ( defined $org_result->entity->user ) { + $c->flash( error => 'Cannot merge from user-owned organisation!' ); + $c->redirect_to( '/admin/organisations/' . $org_id ); + return; } - ); - $c->stash( - org_result => $org_result, - org_rs => $org_rs, - ); + my $org_rs = $c->result_set->search( + { + id => { '!=' => $org_id }, + }, + { + page => $c->param('page') || 1, + rows => 10, + order_by => { '-asc' => 'name' }, + } + ); + + $c->stash( + org_result => $org_result, + org_rs => $org_rs, + ); } sub merge_detail { - my $c = shift; - - my $org_id = $c->param('id'); - my $org_result = $c->result_set->find($org_id); - - if ( defined $org_result->entity->user ) { - $c->flash( error => 'Cannot merge from user-owned organisation!' ); - $c->redirect_to( '/admin/organisations/' . $org_id ); - return; - } - - my $target_id = $c->param('target_id'); - my $target_result = $c->result_set->find($target_id); - - unless ( defined $target_result ) { - $c->flash( error => 'Unknown target organisation' ); - $c->redirect_to( '/admin/organisations/' . $org_id . '/merge' ); - return; - } - - $c->stash( - org_result => $org_result, - target_result => $target_result, - ); + my $c = shift; + + my $org_id = $c->param('id'); + my $org_result = $c->result_set->find($org_id); + + if ( defined $org_result->entity->user ) { + $c->flash( error => 'Cannot merge from user-owned organisation!' ); + $c->redirect_to( '/admin/organisations/' . $org_id ); + return; + } + + my $target_id = $c->param('target_id'); + my $target_result = $c->result_set->find($target_id); + + unless ( defined $target_result ) { + $c->flash( error => 'Unknown target organisation' ); + $c->redirect_to( '/admin/organisations/' . $org_id . '/merge' ); + return; + } + + $c->stash( + org_result => $org_result, + target_result => $target_result, + ); } sub merge_confirm { - my $c = shift; + my $c = shift; - my $org_id = $c->param('id'); - my $org_result = $c->result_set->find($org_id); + my $org_id = $c->param('id'); + my $org_result = $c->result_set->find($org_id); - if ( defined $org_result->entity->user ) { - $c->flash( error => 'Cannot merge from user-owned organisation!' ); - $c->redirect_to( '/admin/organisations/' . $org_id ); - return; - } + if ( defined $org_result->entity->user ) { + $c->flash( error => 'Cannot merge from user-owned organisation!' ); + $c->redirect_to( '/admin/organisations/' . $org_id ); + return; + } - my $target_id = $c->param('target_id'); - my $target_result = $c->result_set->find($target_id); - my $confirm = $c->param('confirm'); + my $target_id = $c->param('target_id'); + my $target_result = $c->result_set->find($target_id); + my $confirm = $c->param('confirm'); - if ( $confirm eq 'checked' && defined $org_result && defined $target_result ) { - try { - $c->schema->txn_do( sub { - # Done as an update, not update_all, so its damn fast - we're only - # editing an id which is guaranteed to be an integer here, and this - # makes it only one update statement. - $org_result->entity->sales->update( - { seller_id => $target_result->entity->id } - ); - my $count = $org_result->entity->sales->count; - die "Failed to migrate all sales" if $count; - $org_result->entity->delete; - $c->schema->resultset('ImportLookup')->search({ entity_id => $org_result->entity->id })->delete; - my $org_count = $c->result_set->search({id => $org_result->id })->count; - my $entity_count = $c->schema->resultset('Entity')->search({id => $org_result->entity->id })->count; - die "Failed to remove org" if $org_count; - die "Failed to remove entity" if $entity_count; - }); - } catch { - $c->app->log->warn($_); - }; - $c->flash( error => 'Engage' ); - } else { - $c->flash( error => 'You must tick the confirmation box to proceed' ); - } - $c->redirect_to( '/admin/organisations/' . $org_id . '/merge/' . $target_id ); + if ( $confirm eq 'checked' + && defined $org_result + && defined $target_result ) + { + try { + $c->schema->txn_do( + sub { + # Done as an update, not update_all, so its damn fast - we're only + # editing an id which is guaranteed to be an integer here, and this + # makes it only one update statement. + $org_result->entity->sales->update( + { seller_id => $target_result->entity->id } ); + my $count = $org_result->entity->sales->count; + die "Failed to migrate all sales" if $count; + $org_result->entity->delete; + $c->schema->resultset('ImportLookup') + ->search( { entity_id => $org_result->entity->id } ) + ->delete; + my $org_count = + $c->result_set->search( { id => $org_result->id } ) + ->count; + my $entity_count = $c->schema->resultset('Entity') + ->search( { id => $org_result->entity->id } )->count; + die "Failed to remove org" if $org_count; + die "Failed to remove entity" if $entity_count; + } + ); + } + catch { + $c->app->log->warn($_); + }; + $c->flash( error => 'Engage' ); + } + else { + $c->flash( error => 'You must tick the confirmation box to proceed' ); + } + $c->redirect_to( + '/admin/organisations/' . $org_id . '/merge/' . $target_id ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm index 5d0991f..fece5ee 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm @@ -4,77 +4,78 @@ use Mojo::Base 'Mojolicious::Controller'; use Mojo::JSON qw/ encode_json /; sub transaction_data { - my $c = shift; + my $c = shift; - my $quantised_column = 'quantised_hours'; - if ( defined $c->param('scale') && $c->param('scale') eq 'days' ) { - $quantised_column = 'quantised_days'; - } + my $quantised_column = 'quantised_hours'; + if ( defined $c->param('scale') && $c->param('scale') eq 'days' ) { + $quantised_column = 'quantised_days'; + } - my $driver = $c->schema->storage->dbh->{Driver}->{Name}; - my $transaction_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( - {}, - { - columns => [ + my $driver = $c->schema->storage->dbh->{Driver}->{Name}; + my $transaction_rs = + $c->schema->resultset( 'ViewQuantisedTransaction' . $driver )->search( + {}, { - 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")', - ), + columns => [ + { + 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")', + ), + } + ], + group_by => $quantised_column, + order_by => { '-asc' => $quantised_column }, } - ], - group_by => $quantised_column, - order_by => { '-asc' => $quantised_column }, - } - ); + ); - 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 - ]; + 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->respond_to( - json => { json => { data => $transaction_data } }, - html => { transaction_rs => encode_json( $transaction_data ) }, - ); + $c->respond_to( + json => { json => { data => $transaction_data } }, + html => { transaction_rs => encode_json($transaction_data) }, + ); } sub pg_or_sqlite { - my ( $c, $pg_sql, $sqlite_sql ) = @_; + my ( $c, $pg_sql, $sqlite_sql ) = @_; - my $driver = $c->schema->storage->dbh->{Driver}->{Name}; + 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; - } + if ( $driver eq 'Pg' ) { + return \$pg_sql; + } + elsif ( $driver eq 'SQLite' ) { + return \$sqlite_sql; + } + else { + $c->app->log->warn('Unknown Driver Used'); + return; + } } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm b/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm index 5fec0cb..67481c5 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm @@ -2,96 +2,109 @@ package Pear::LocalLoop::Controller::Admin::Tokens; use Mojo::Base 'Mojolicious::Controller'; has result_set => sub { - my $c = shift; - return $c->schema->resultset('AccountToken'); + my $c = shift; + return $c->schema->resultset('AccountToken'); }; sub index { - my $c = shift; + my $c = shift; - my $token_rs = $c->result_set; - $token_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); - $c->stash( tokens => [ $token_rs->all ] ); + my $token_rs = $c->result_set; + $token_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); + $c->stash( tokens => [ $token_rs->all ] ); } # POST sub create { - my $c = shift; - - my $validation = $c->validation; - $validation->required('token', 'trim')->like(qr/^[\w]*$/)->not_in_resultset('name', $c->result_set); - - my $token_name = $validation->param('token'); - - if ( $validation->has_error ) { - my $check = shift @{ $c->validation->error('token') }; - if ( $check eq 'required' ) { - $c->flash( error => 'Token name is required' ); - } elsif ( $check eq 'like' ) { - $c->flash( error => 'Token name not valid - Alphanumeric characters and Underscore only' ); - } elsif ( $check eq 'not_in_resultset' ) { - $c->flash( error => 'Token Already Exists' ); - } - } else { - $c->flash( success => 'Token Created' ); - $c->result_set->create({ name => $token_name }); - } - $c->redirect_to( '/admin/tokens' ); + my $c = shift; + + my $validation = $c->validation; + $validation->required( 'token', 'trim' )->like(qr/^[\w]*$/) + ->not_in_resultset( 'name', $c->result_set ); + + my $token_name = $validation->param('token'); + + if ( $validation->has_error ) { + my $check = shift @{ $c->validation->error('token') }; + if ( $check eq 'required' ) { + $c->flash( error => 'Token name is required' ); + } + elsif ( $check eq 'like' ) { + $c->flash( error => +'Token name not valid - Alphanumeric characters and Underscore only' + ); + } + elsif ( $check eq 'not_in_resultset' ) { + $c->flash( error => 'Token Already Exists' ); + } + } + else { + $c->flash( success => 'Token Created' ); + $c->result_set->create( { name => $token_name } ); + } + $c->redirect_to('/admin/tokens'); } # GET sub read { - my $c = shift; + my $c = shift; - my $id = $c->param('id'); + my $id = $c->param('id'); - if ( my $token = $c->result_set->find($id) ) { - $c->stash( token => $token ); - } else { - $c->flash( error => 'No Token found' ); - $c->redirect_to( '/admin/tokens' ); - } + if ( my $token = $c->result_set->find($id) ) { + $c->stash( token => $token ); + } + else { + $c->flash( error => 'No Token found' ); + $c->redirect_to('/admin/tokens'); + } } # POST sub update { - my $c = shift; - my $validation = $c->validation; - $validation->required('token', 'trim')->like(qr/^[\w]*$/); - $validation->required('used')->in( qw/ 0 1 / ); - - my $id = $c->param('id'); - - if ( $validation->has_error ) { - my $names = $validation->failed; - $c->flash( error => 'Error in submitted data: ' . join(', ', @$names) ); - $c->redirect_to( '/admin/tokens/' . $id ); - } elsif ( my $token = $c->result_set->find($id) ) { - $token->update({ - name => $validation->param('token'), - used => $validation->param('used'), - }); - $c->flash( success => 'Token Updated' ); - $c->redirect_to( '/admin/tokens/' . $id ); - } else { - $c->flash( error => 'No Token found' ); - $c->redirect_to( '/admin/tokens' ); - } + my $c = shift; + my $validation = $c->validation; + $validation->required( 'token', 'trim' )->like(qr/^[\w]*$/); + $validation->required('used')->in(qw/ 0 1 /); + + my $id = $c->param('id'); + + if ( $validation->has_error ) { + my $names = $validation->failed; + $c->flash( + error => 'Error in submitted data: ' . join( ', ', @$names ) ); + $c->redirect_to( '/admin/tokens/' . $id ); + } + elsif ( my $token = $c->result_set->find($id) ) { + $token->update( + { + name => $validation->param('token'), + used => $validation->param('used'), + } + ); + $c->flash( success => 'Token Updated' ); + $c->redirect_to( '/admin/tokens/' . $id ); + } + else { + $c->flash( error => 'No Token found' ); + $c->redirect_to('/admin/tokens'); + } } # DELETE sub delete { - my $c = shift; - - my $id = $c->param('id'); - - if ( my $token = $c->result_set->find($id) ) { - $token->delete; - $c->flash( success => 'Token Deleted' ); - } else { - $c->flash( error => 'No Token found' ); - } - $c->redirect_to( '/admin/tokens' ); + my $c = shift; + + my $id = $c->param('id'); + + if ( my $token = $c->result_set->find($id) ) { + $token->delete; + $c->flash( success => 'Token Deleted' ); + } + else { + $c->flash( error => 'No Token found' ); + } + $c->redirect_to('/admin/tokens'); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm index bf3056b..f9cf3ee 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm @@ -4,117 +4,133 @@ use Mojo::Base 'Mojolicious::Controller'; use List::Util qw/ max sum /; has result_set => sub { - my $c = shift; - return $c->schema->resultset('Transaction'); + my $c = shift; + return $c->schema->resultset('Transaction'); }; sub index { - my $c = shift; - - my $pending_transaction_rs = $c->schema->resultset('Organisation')->search({ pending => 1 })->entity->sales; - - my $driver = $c->schema->storage->dbh->{Driver}->{Name}; - my $week_transaction_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( - {}, - { - select => [ - { count => 'me.value', '-as' => 'count' }, - { sum => 'me.value', '-as' => 'sum_value' }, - 'quantised_weeks', - ], - group_by => 'quantised_weeks', - order_by => { '-asc' => 'quantised_weeks' }, - } - ); - - my @all_weeks = $week_transaction_rs->all; - my $first_week_count = defined $all_weeks[0] ? $all_weeks[0]->get_column('count') || 0 : 0; - my $first_week_value = defined $all_weeks[0] ? $all_weeks[0]->get_column('sum_value') / 100000 || 0 : 0; - my $second_week_count = defined $all_weeks[1] ? $all_weeks[1]->get_column('count') || 0 : 0; - my $second_week_value = defined $all_weeks[1] ? $all_weeks[1]->get_column('sum_value') / 100000 || 0 : 0; - - my $transaction_rs = $c->schema->resultset('Transaction'); - my $value_rs_col = $transaction_rs->get_column('value'); - my $max_value = $value_rs_col->max / 100000 || 0; - my $avg_value = sprintf( '%.2f', $value_rs_col->func('AVG') / 100000) || 0; - my $sum_value = $value_rs_col->sum / 100000 || 0; - my $count = $transaction_rs->count || 0; - - my $placeholder = 'Placeholder'; - $c->stash( - placeholder => $placeholder, - pending_trans => $pending_transaction_rs->count, - weeks => { - first_count => $first_week_count, - second_count => $second_week_count, - first_value => $first_week_value, - second_value => $second_week_value, - max => $max_value, - avg => $avg_value, - sum => $sum_value, - count => $count, - }, - ); + my $c = shift; + + my $pending_transaction_rs = + $c->schema->resultset('Organisation')->search( { pending => 1 } ) + ->entity->sales; + + my $driver = $c->schema->storage->dbh->{Driver}->{Name}; + my $week_transaction_rs = + $c->schema->resultset( 'ViewQuantisedTransaction' . $driver )->search( + {}, + { + select => [ + { count => 'me.value', '-as' => 'count' }, + { sum => 'me.value', '-as' => 'sum_value' }, + 'quantised_weeks', + ], + group_by => 'quantised_weeks', + order_by => { '-asc' => 'quantised_weeks' }, + } + ); + + my @all_weeks = $week_transaction_rs->all; + my $first_week_count = + defined $all_weeks[0] ? $all_weeks[0]->get_column('count') || 0 : 0; + my $first_week_value = + defined $all_weeks[0] + ? $all_weeks[0]->get_column('sum_value') / 100000 || 0 + : 0; + my $second_week_count = + defined $all_weeks[1] ? $all_weeks[1]->get_column('count') || 0 : 0; + my $second_week_value = + defined $all_weeks[1] + ? $all_weeks[1]->get_column('sum_value') / 100000 || 0 + : 0; + + my $transaction_rs = $c->schema->resultset('Transaction'); + my $value_rs_col = $transaction_rs->get_column('value'); + my $max_value = $value_rs_col->max / 100000 || 0; + my $avg_value = sprintf( '%.2f', $value_rs_col->func('AVG') / 100000 ) || 0; + my $sum_value = $value_rs_col->sum / 100000 || 0; + my $count = $transaction_rs->count || 0; + + my $placeholder = 'Placeholder'; + $c->stash( + placeholder => $placeholder, + pending_trans => $pending_transaction_rs->count, + weeks => { + first_count => $first_week_count, + second_count => $second_week_count, + first_value => $first_week_value, + second_value => $second_week_value, + max => $max_value, + avg => $avg_value, + sum => $sum_value, + count => $count, + }, + ); } sub read { - my $c = shift; + my $c = shift; - my $id = $c->param('id'); + my $id = $c->param('id'); - if ( my $transaction = $c->result_set->find($id) ) { - $c->stash( transaction => $transaction ); - } else { - $c->flash( error => 'No transaction found' ); - $c->redirect_to( '/admin/transactions' ); - } + if ( my $transaction = $c->result_set->find($id) ) { + $c->stash( transaction => $transaction ); + } + else { + $c->flash( error => 'No transaction found' ); + $c->redirect_to('/admin/transactions'); + } } sub image { - my $c = shift; + my $c = shift; - my $id = $c->param('id'); + my $id = $c->param('id'); - my $transaction = $c->result_set->find($id); + my $transaction = $c->result_set->find($id); - if ( $transaction->proof_image ) { - $c->reply->asset($c->get_file_from_uuid($transaction->proof_image)); - } else { - $c->reply->static('image/no_transaction.jpg'); - } + if ( $transaction->proof_image ) { + $c->reply->asset( $c->get_file_from_uuid( $transaction->proof_image ) ); + } + else { + $c->reply->static('image/no_transaction.jpg'); + } } sub delete { - my $c = shift; + my $c = shift; - my $id = $c->param('id'); + my $id = $c->param('id'); -if ( my $transaction = $c->result_set->find($id) ) { - if (defined $transaction->category) { - $transaction->category->delete; + if ( my $transaction = $c->result_set->find($id) ) { + if ( defined $transaction->category ) { + $transaction->category->delete; + } + $transaction->delete; + $c->flash( success => 'Successfully deleted transaction' ); + $c->redirect_to('/admin/transactions'); + } + else { + $c->flash( error => 'No transaction found' ); + $c->redirect_to('/admin/transactions'); } - $transaction->delete; - $c->flash( success => 'Successfully deleted transaction' ); - $c->redirect_to( '/admin/transactions' ); - } else { - $c->flash( error => 'No transaction found' ); - $c->redirect_to( '/admin/transactions' ); - } } 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; - } + 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; + } } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Users.pm b/lib/Pear/LocalLoop/Controller/Admin/Users.pm index a1d4aef..a808a06 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Users.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Users.pm @@ -5,150 +5,190 @@ use Try::Tiny; use Data::Dumper; has user_result_set => sub { - my $c = shift; - return $c->schema->resultset('User'); + my $c = shift; + return $c->schema->resultset('User'); }; has customer_result_set => sub { - my $c = shift; - return $c->schema->resultset('Customer'); + my $c = shift; + return $c->schema->resultset('Customer'); }; has organisation_result_set => sub { - my $c = shift; - return $c->schema->resultset('Organisation'); + my $c = shift; + return $c->schema->resultset('Organisation'); }; sub index { - my $c = shift; - - my $user_rs = $c->user_result_set->search( - undef, { - prefech => { entity => [ qw/ customer organisation / ] }, - page => $c->param('page') || 1, - rows => 10, - order_by => { -asc => 'email' }, - } - ); - $c->stash( user_rs => $user_rs ); + my $c = shift; + + my $user_rs = $c->user_result_set->search( + undef, + { + prefech => { entity => [qw/ customer organisation /] }, + page => $c->param('page') || 1, + rows => 10, + order_by => { -asc => 'email' }, + } + ); + $c->stash( user_rs => $user_rs ); } sub read { - my $c = shift; + my $c = shift; + + my $id = $c->param('id'); + + if ( my $user = $c->user_result_set->find($id) ) { + my $transactions = $user->entity->purchases->search( + undef, + { + page => $c->param('page') || 1, + rows => 10, + order_by => { -desc => 'submitted_at' }, + }, + ); + $c->stash( + user => $user, + transactions => $transactions, + ); + } + else { + $c->flash( error => 'No User found' ); + $c->redirect_to('/admin/users'); + } +} - my $id = $c->param('id'); +sub update { + my $c = shift; - if ( my $user = $c->user_result_set->find($id) ) { - my $transactions = $user->entity->purchases->search( - undef, { - page => $c->param('page') || 1, - rows => 10, - order_by => { -desc => 'submitted_at' }, - }, - ); - $c->stash( - user => $user, - transactions => $transactions, + my $id = $c->param('id'); + + my $user; + + unless ( $user = $c->user_result_set->find($id) ) { + $c->flash( error => 'No User found' ); + return $c->redirect_to( '/admin/users/' . $id ); + } + + my $validation = $c->validation; + + my $not_myself_user_rs = $c->user_result_set->search( + { + id => { "!=" => $user->id }, + } ); - } else { - $c->flash( error => 'No User found' ); - $c->redirect_to( '/admin/users' ); - } -} + $validation->required('email') + ->email->not_in_resultset( 'email', $not_myself_user_rs ); + $validation->required('postcode')->postcode; + $validation->optional('new_password'); + + if ( $user->type eq 'customer' ) { + $validation->required('display_name'); + $validation->required('full_name'); + } + elsif ( $user->type eq 'organisation' ) { + $validation->required('name'); + $validation->required('street_name'); + $validation->required('town'); + $validation->optional('sector'); + } -sub update { - my $c = shift; - - my $id = $c->param('id'); - - my $user; - - unless ( $user = $c->user_result_set->find($id) ) { - $c->flash( error => 'No User found' ); - return $c->redirect_to( '/admin/users/' . $id ); - } - - my $validation = $c->validation; - - my $not_myself_user_rs = $c->user_result_set->search({ - id => { "!=" => $user->id }, - }); - $validation->required('email')->email->not_in_resultset( 'email', $not_myself_user_rs ); - $validation->required('postcode')->postcode; - $validation->optional('new_password'); - - if ( $user->type eq 'customer' ) { - $validation->required('display_name'); - $validation->required('full_name'); - } elsif ( $user->type eq 'organisation' ) { - $validation->required('name'); - $validation->required('street_name'); - $validation->required('town'); - $validation->optional('sector'); - } - - if ( $validation->has_error ) { - $c->flash( error => 'The validation has failed' ); - return $c->redirect_to( '/admin/users/' . $id ); - } - - my $location = $c->get_location_from_postcode( - $validation->param('postcode'), - $user->type, - ); - - if ( $user->type eq 'customer' ){ - - try { - $c->schema->txn_do( sub { - $user->entity->customer->update({ - full_name => $validation->param('full_name'), - display_name => $validation->param('display_name'), - postcode => $validation->param('postcode'), - ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), - }); - $user->update({ - email => $validation->param('email'), - ( defined $validation->param('new_password') ? ( password => $validation->param('new_password') ) : () ), - }); - }); - } finally { - if ( @_ ) { - $c->flash( error => 'Something went wrong Updating the User' ); - $c->app->log->warn(Dumper @_); - } else { - $c->flash( success => 'Updated User' ); - }; + if ( $validation->has_error ) { + $c->flash( error => 'The validation has failed' ); + return $c->redirect_to( '/admin/users/' . $id ); + } + + my $location = + $c->get_location_from_postcode( $validation->param('postcode'), + $user->type, ); + + if ( $user->type eq 'customer' ) { + + try { + $c->schema->txn_do( + sub { + $user->entity->customer->update( + { + full_name => $validation->param('full_name'), + display_name => $validation->param('display_name'), + postcode => $validation->param('postcode'), + ( + defined $location + ? (%$location) + : ( latitude => undef, longitude => undef ) + ), + } + ); + $user->update( + { + email => $validation->param('email'), + ( + defined $validation->param('new_password') + ? ( password => + $validation->param('new_password') ) + : () + ), + } + ); + } + ); + } + finally { + if (@_) { + $c->flash( error => 'Something went wrong Updating the User' ); + $c->app->log->warn( Dumper @_ ); + } + else { + $c->flash( success => 'Updated User' ); + } + } } - } - elsif ( $user->type eq 'organisation' ) { - - try { - $c->schema->txn_do( sub { - $user->entity->organisation->update({ - name => $validation->param('name'), - street_name => $validation->param('street_name'), - town => $validation->param('town'), - sector => $validation->param('sector'), - postcode => $validation->param('postcode'), - ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), - }); - $user->update({ - email => $validation->param('email'), - ( defined $validation->param('new_password') ? ( password => $validation->param('new_password') ) : () ), - }); - }); - } finally { - if ( @_ ) { - $c->flash( error => 'Something went wrong Updating the User' ); - $c->app->log->warn(Dumper @_); - } else { - $c->flash( success => 'Updated User' ); - } + elsif ( $user->type eq 'organisation' ) { + + try { + $c->schema->txn_do( + sub { + $user->entity->organisation->update( + { + name => $validation->param('name'), + street_name => $validation->param('street_name'), + town => $validation->param('town'), + sector => $validation->param('sector'), + postcode => $validation->param('postcode'), + ( + defined $location + ? (%$location) + : ( latitude => undef, longitude => undef ) + ), + } + ); + $user->update( + { + email => $validation->param('email'), + ( + defined $validation->param('new_password') + ? ( password => + $validation->param('new_password') ) + : () + ), + } + ); + } + ); + } + finally { + if (@_) { + $c->flash( error => 'Something went wrong Updating the User' ); + $c->app->log->warn( Dumper @_ ); + } + else { + $c->flash( success => 'Updated User' ); + } + } } - }; - $c->redirect_to( '/admin/users/' . $id ); + $c->redirect_to( '/admin/users/' . $id ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/Auth.pm b/lib/Pear/LocalLoop/Controller/Api/Auth.pm index 2f44b10..cb03903 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Auth.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Auth.pm @@ -4,131 +4,141 @@ use Data::Dumper; use Mojo::JSON qw/ decode_json /; has error_messages => sub { - return { - email => { - required => { message => 'No email sent.', status => 400 }, - email => { message => 'Email is invalid.', status => 400 }, - }, - password => { - required => { message => 'No password sent.', status => 400 }, - }, - }; + return { + email => { + required => { message => 'No email sent.', status => 400 }, + email => { message => 'Email is invalid.', status => 400 }, + }, + password => { + required => { message => 'No password sent.', status => 400 }, + }, + }; }; sub check_json { - my $c = shift; - - # JSON object is either the whole request, or under a json param for upload - my $json = $c->req->json || decode_json( $c->param('json') || '{}' ); - - unless ( defined $json && ref $json eq 'HASH' && scalar( keys %$json ) > 0 ) { - $c->render( - json => { - success => Mojo::JSON->false, - message => 'JSON is missing.', - }, - status => 400, - ); - return 0; - } + my $c = shift; + + # JSON object is either the whole request, or under a json param for upload + my $json = $c->req->json || decode_json( $c->param('json') || '{}' ); + + unless ( defined $json && ref $json eq 'HASH' && scalar( keys %$json ) > 0 ) + { + $c->render( + json => { + success => Mojo::JSON->false, + message => 'JSON is missing.', + }, + status => 400, + ); + return 0; + } - $c->stash( api_json => $json ); - return 1; + $c->stash( api_json => $json ); + return 1; } sub auth { - my $c = shift; + my $c = shift; - my $session_key = $c->stash->{api_json}->{session_key}; + my $session_key = $c->stash->{api_json}->{session_key}; - if ( defined $session_key ) { - my $session_result = $c->schema->resultset('SessionToken')->find({ token => $session_key }); + if ( defined $session_key ) { + my $session_result = $c->schema->resultset('SessionToken') + ->find( { token => $session_key } ); - if ( defined $session_result ) { - $c->stash( api_user => $session_result->user ); - return 1; + if ( defined $session_result ) { + $c->stash( api_user => $session_result->user ); + return 1; + } } - } - - $c->render( - json => { - success => Mojo::JSON->false, - message => 'Invalid Session', - }, - status => 401, - ); - return 0; + + $c->render( + json => { + success => Mojo::JSON->false, + message => 'Invalid Session', + }, + status => 401, + ); + return 0; } sub test_connection { - my $c = shift; - - return $c->render( - json => { - success => Mojo::JSON->true, - message => 'Database connection successful', - }, - status => 200, - ); + my $c = shift; + + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Database connection successful', + }, + status => 200, + ); } sub post_login { - my $c = shift; - - my $validation = $c->validation; - - $validation->input( $c->stash->{api_json} ); - $validation->required('email')->email; - $validation->required('password'); - - return $c->api_validation_error if $validation->has_error; - - my $email = $validation->param('email'); - my $password = $validation->param('password'); - - $c->app->log->debug( __PACKAGE__ . " login attempt for [" . $email . "]" ); - - my $user_result = $c->schema->resultset('User')->find({ email => $email }); - - if ( defined $user_result ) { - if ( $user_result->check_password($password) ) { - my $session_key = $user_result->generate_session; - - return $c->render( json => { - success => Mojo::JSON->true, - session_key => $session_key, - email => $email, - display_name => $user_result->name, - user_type => $user_result->type, - }); - } else { - $c->app->log->info( __PACKAGE__ . " failed login for [" . $email . "]" ); + my $c = shift; + + my $validation = $c->validation; + + $validation->input( $c->stash->{api_json} ); + $validation->required('email')->email; + $validation->required('password'); + + return $c->api_validation_error if $validation->has_error; + + my $email = $validation->param('email'); + my $password = $validation->param('password'); + + $c->app->log->debug( __PACKAGE__ . " login attempt for [" . $email . "]" ); + + my $user_result = + $c->schema->resultset('User')->find( { email => $email } ); + + if ( defined $user_result ) { + if ( $user_result->check_password($password) ) { + my $session_key = $user_result->generate_session; + + return $c->render( + json => { + success => Mojo::JSON->true, + session_key => $session_key, + email => $email, + display_name => $user_result->name, + user_type => $user_result->type, + } + ); + } + else { + $c->app->log->info( + __PACKAGE__ . " failed login for [" . $email . "]" ); + } } - } - return $c->render( - json => { - success => Mojo::JSON->false, - message => 'Email or password is invalid.', - }, - status => 401 - ); + return $c->render( + json => { + success => Mojo::JSON->false, + message => 'Email or password is invalid.', + }, + status => 401 + ); } sub post_logout { - my $c = shift; + my $c = shift; - my $session_key = $c->req->json( '/session_key' ); + my $session_key = $c->req->json('/session_key'); - my $session_result = $c->schema->resultset('SessionToken')->find({ token => $session_key }); + my $session_result = + $c->schema->resultset('SessionToken')->find( { token => $session_key } ); - if ( defined $session_result ) { - $session_result->delete; - } + if ( defined $session_result ) { + $session_result->delete; + } - $c->render( json => { - success => Mojo::JSON->true, - message => 'Logged Out', - }); + $c->render( + json => { + success => Mojo::JSON->true, + message => 'Logged Out', + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/Categories.pm b/lib/Pear/LocalLoop/Controller/Api/Categories.pm index 84bd9c1..8c96e6b 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Categories.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Categories.pm @@ -4,83 +4,93 @@ use Mojo::Base 'Mojolicious::Controller'; use List::Util qw/ max /; sub post_category_list { - my $c = shift; + my $c = shift; - my $entity = $c->stash->{api_user}->entity; + 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 $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 => [ + 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( { - quantised => 'quantised_weeks', - value => { sum => 'value' }, - category_id => 'category_id', - essential => 'essential', + purchase_time => { + -between => [ + $dtf->format_datetime($start), + $dtf->format_datetime($end), + ], + }, + buyer_id => $entity->id, }, - ], - group_by => [ qw/ category_id quantised_weeks essential / ], - } - ); - - my $data = { categories => {}, essentials => {} }; + { + 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; + my $data = { categories => {}, essentials => {} }; - 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; - } + my $category_list = $c->schema->resultset('Category')->as_hash; - 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 ]; - } + 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; + } - return $c->render( - json => { - success => Mojo::JSON->true, - data => $data, + 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, + } + ); } sub pg_or_sqlite { - my ( $c, $pg_sql, $sqlite_sql ) = @_; + my ( $c, $pg_sql, $sqlite_sql ) = @_; - my $driver = $c->schema->storage->dbh->{Driver}->{Name}; + 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; - } + if ( $driver eq 'Pg' ) { + return \$pg_sql; + } + elsif ( $driver eq 'SQLite' ) { + return \$sqlite_sql; + } + else { + $c->app->log->warn('Unknown Driver Used'); + return; + } } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/Devices.pm b/lib/Pear/LocalLoop/Controller/Api/Devices.pm index c8fcf4c..7c91143 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Devices.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Devices.pm @@ -5,126 +5,144 @@ use JSON; use Mojo::File; has error_messages => sub { - return { - token => { - required => { message => 'Token is required', status => 400 }, - not_in_resultset => { message => 'Token already in database', status => 400 }, - }, - email => { - required => { message => 'User email is required', status => 400 }, - in_resultset => { message => 'User email not recognised', status => 400 }, - }, - }; + return { + token => { + required => { message => 'Token is required', status => 400 }, + not_in_resultset => + { message => 'Token already in database', status => 400 }, + }, + email => { + required => { message => 'User email is required', status => 400 }, + in_resultset => + { message => 'User email not recognised', status => 400 }, + }, + }; }; sub check_token { - my $c = shift; + my $c = shift; - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); - $validation->required('token'); + $validation->required('token'); - my $token = $validation->param('token'); - my $token_rs = $c->schema->resultset('DeviceToken')->search({'token' => $token}); + my $token = $validation->param('token'); + my $token_rs = + $c->schema->resultset('DeviceToken')->search( { 'token' => $token } ); - if ($token_rs->count > 0) { - return $c->render( json => { - exists => Mojo::JSON->true - }); - } else { - return $c->render( json => { - exists => Mojo::JSON->false - }); - } + if ( $token_rs->count > 0 ) { + return $c->render( + json => { + exists => Mojo::JSON->true + } + ); + } + else { + return $c->render( + json => { + exists => Mojo::JSON->false + } + ); + } } sub add_token { - my $c = shift; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - - my $token_rs = $c->schema->resultset('DeviceToken'); - my $user_rs = $c->schema->resultset('User'); - - # TODO: validate that prexisting tokens are connected to the logged-in user - $validation->required('email')->in_resultset( 'email', $user_rs ); - $validation->required('token')->not_in_resultset( 'token', $token_rs ); - - return $c->api_validation_error if $validation->has_error; - - my $user = $user_rs->find({'email' => $validation->param('email')}); - - my $token = $validation->param('token'); - - $user->create_related( - 'device_tokens', - { - token => $token, - } - ); - - my $end_point = "https://iid.googleapis.com/iid/v1/${token}/rel/topics/default"; - - my $path = './localspend-47012.json'; - my $json = decode_json(Mojo::File->new($path)->slurp); - croak("No Private key in $path") if not defined $json->{server_key}; - croak("Not a service account") if $json->{type} ne 'service_account'; - - my $ua = LWP::UserAgent->new(); - my $request = HTTP::Request->new('POST', $end_point); - - $request->header('Authorization' => 'key='.$json->{server_key}); - $request->header('Content-Length' => '0'); - my $response = $ua->request($request); - - if ($response->is_success) { - my $deviceToken = $c->schema->resultset('DeviceToken')->find({'token' => $token}); - my $topic = $c->schema->resultset('Topic')->find({'name' => 'default'}); - - $deviceToken->create_related( - 'device_subscriptions', - { - topic => $topic - } + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + my $token_rs = $c->schema->resultset('DeviceToken'); + my $user_rs = $c->schema->resultset('User'); + + # TODO: validate that prexisting tokens are connected to the logged-in user + $validation->required('email')->in_resultset( 'email', $user_rs ); + $validation->required('token')->not_in_resultset( 'token', $token_rs ); + + return $c->api_validation_error if $validation->has_error; + + my $user = $user_rs->find( { 'email' => $validation->param('email') } ); + + my $token = $validation->param('token'); + + $user->create_related( + 'device_tokens', + { + token => $token, + } ); - return $c->render( json => { - success => Mojo::JSON->true, - message => 'Device registered successfully!', - }); - } elsif ($response->is_error) { - return $c->render( - json => { - success => Mojo::JSON->false, - message => [ - $response->decoded_content, - ], - error => 'subscription_error', - }, - status => $response->code, - ); - } + my $end_point = + "https://iid.googleapis.com/iid/v1/${token}/rel/topics/default"; + + my $path = './localspend-47012.json'; + my $json = decode_json( Mojo::File->new($path)->slurp ); + croak("No Private key in $path") if not defined $json->{server_key}; + croak("Not a service account") if $json->{type} ne 'service_account'; + + my $ua = LWP::UserAgent->new(); + my $request = HTTP::Request->new( 'POST', $end_point ); + + $request->header( 'Authorization' => 'key=' . $json->{server_key} ); + $request->header( 'Content-Length' => '0' ); + my $response = $ua->request($request); + + if ( $response->is_success ) { + my $deviceToken = + $c->schema->resultset('DeviceToken')->find( { 'token' => $token } ); + my $topic = + $c->schema->resultset('Topic')->find( { 'name' => 'default' } ); + + $deviceToken->create_related( + 'device_subscriptions', + { + topic => $topic + } + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Device registered successfully!', + } + ); + } + elsif ( $response->is_error ) { + return $c->render( + json => { + success => Mojo::JSON->false, + message => [ $response->decoded_content, ], + error => 'subscription_error', + }, + status => $response->code, + ); + } } sub get_tokens { - my $c = shift; - - my $token_rs = $c->schema->resultset('DeviceToken'); - - my @tokens = ( - map {{ - id => $_->id, - user => $c->schema->resultset('User')->find({'id' => $_->user_id})->entity->customer->display_name, - token => $_->token, - }} $token_rs->all - ); - - return $c->render( json => { - success => Mojo::JSON->true, - tokens => \@tokens, - }); + my $c = shift; + + my $token_rs = $c->schema->resultset('DeviceToken'); + + my @tokens = ( + map { + { + id => $_->id, + user => $c->schema->resultset('User') + ->find( { 'id' => $_->user_id } ) + ->entity->customer->display_name, + token => $_->token, + } + } $token_rs->all + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + tokens => \@tokens, + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/External.pm b/lib/Pear/LocalLoop/Controller/Api/External.pm index 6167f81..efae6ae 100644 --- a/lib/Pear/LocalLoop/Controller/Api/External.pm +++ b/lib/Pear/LocalLoop/Controller/Api/External.pm @@ -3,487 +3,529 @@ use Mojo::Base 'Mojolicious::Controller'; use Mojo::JSON; sub post_lcc_transactions { - my $c = shift; + my $c = shift; - my $user = $c->stash->{api_user}; + my $user = $c->stash->{api_user}; - # TODO Check the user is lancaster city council + # TODO Check the user is lancaster city council - my $validation = $c->validation; - $validation->input($c->stash->{api_json}); - $validation->optional('page')->number; - $validation->optional('per_page')->number; - $validation->optional('search'); + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->optional('page')->number; + $validation->optional('per_page')->number; + $validation->optional('search'); - return $c->api_validation_error if $validation->has_error; + return $c->api_validation_error if $validation->has_error; - my $search_ref = { 'me.buyer_id' => $user->entity->id }; - if ($validation->param('search')) { - $search_ref->{"organisation.name"} = { '-like' => join('', '%', $validation->param('search'), '%') }; - } + my $search_ref = { 'me.buyer_id' => $user->entity->id }; + if ( $validation->param('search') ) { + $search_ref->{"organisation.name"} = + { '-like' => join( '', '%', $validation->param('search'), '%' ) }; + } - my $lcc_transactions = $c->schema->resultset('Transaction')->search( - $search_ref, - { - page => $validation->param('page') || 1, - rows => $validation->param('per_page') || 10, - join => [ 'transaction', 'organisation' ], - order_by => { -desc => 'transaction.purchase_time' }, - }); - - # purchase_time needs timezone attached to it - my @transaction_list = ( - map {{ - transaction_external_id => $_->external_id, - seller => $_->transaction->seller->name, - net_value => $_->transaction->meta->net_value, - gross_value => $_->transaction->meta->gross_value, - sales_tax_value => $_->transaction->meta->sales_tax_value, - purchase_time => $c->format_iso_datetime($_->transaction->purchase_time), - }} $lcc_transactions->all - ); - - return $c->render(json => { - success => Mojo::JSON->true, - transactions => \@transaction_list, - page_no => $lcc_transactions->pager->total_entries, - }); + my $lcc_transactions = $c->schema->resultset('Transaction')->search( + $search_ref, + { + page => $validation->param('page') || 1, + rows => $validation->param('per_page') || 10, + join => [ 'transaction', 'organisation' ], + order_by => { -desc => 'transaction.purchase_time' }, + } + ); + + # purchase_time needs timezone attached to it + my @transaction_list = ( + map { + { + transaction_external_id => $_->external_id, + seller => $_->transaction->seller->name, + net_value => $_->transaction->meta->net_value, + gross_value => $_->transaction->meta->gross_value, + sales_tax_value => $_->transaction->meta->sales_tax_value, + purchase_time => + $c->format_iso_datetime( $_->transaction->purchase_time ), + } + } $lcc_transactions->all + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + transactions => \@transaction_list, + page_no => $lcc_transactions->pager->total_entries, + } + ); } sub post_lcc_suppliers { - my $c = shift; - - my $user = $c->stash->{api_user}; - - # TODO give an error if user is not of Lancashire County Council - - # my $is_lcc = $user->entity->organisation->count({ name => "Lancashire County Council" }); - - my $v = $c->validation; - $v->input($c->stash->{api_json}); - $v->optional('page')->number; - $v->optional('sort_by'); - $v->optional('sort_dir'); - $v->optional('search'); - - my $order_by = [ - { -asc => 'organisation.name' }, - ]; - if ($v->param('sort_by')) { - my %dirs = ('asc' => '-asc', 'desc' => '-desc'); - my $dir = $dirs{$v->param('sort_dir')} // '-asc'; - my %sorts = ( - 'name' => 'organisation.name', - 'postcode' => 'organisation.postcode', - 'spend' => 'total_spend', - ); - my $sort = $sorts{$v->param('sort_by')} || 'organisation.name'; - $order_by->[0] = { $dir => $sort }; - } + my $c = shift; + + my $user = $c->stash->{api_user}; + + # TODO give an error if user is not of Lancashire County Council + +# my $is_lcc = $user->entity->organisation->count({ name => "Lancashire County Council" }); + + my $v = $c->validation; + $v->input( $c->stash->{api_json} ); + $v->optional('page')->number; + $v->optional('sort_by'); + $v->optional('sort_dir'); + $v->optional('search'); + + my $order_by = [ { -asc => 'organisation.name' }, ]; + if ( $v->param('sort_by') ) { + my %dirs = ( 'asc' => '-asc', 'desc' => '-desc' ); + my $dir = $dirs{ $v->param('sort_dir') } // '-asc'; + my %sorts = ( + 'name' => 'organisation.name', + 'postcode' => 'organisation.postcode', + 'spend' => 'total_spend', + ); + my $sort = $sorts{ $v->param('sort_by') } || 'organisation.name'; + $order_by->[0] = { $dir => $sort }; + } - return $c->api_validation_error if $v->has_error; + return $c->api_validation_error if $v->has_error; - my $lcc_suppliers = $c->schema->resultset('Entity')->search( - { - 'sales.buyer_id' => $user->entity->id, - ($v->param('search') ? ( - '-or' => [ - { 'organisation.name' => { 'like' => $v->param('search') . '%' } }, - { 'organisation.postcode' => { 'like' => $v->param('search') . '%' } }, - ] - ) : ()), - }, - { - join => [ 'sales', 'organisation' ], - group_by => [ 'me.id', 'organisation.id' ], - '+select' => [ + my $lcc_suppliers = $c->schema->resultset('Entity')->search( + { + 'sales.buyer_id' => $user->entity->id, + ( + $v->param('search') + ? ( + '-or' => [ + { + 'organisation.name' => + { 'like' => $v->param('search') . '%' } + }, + { + 'organisation.postcode' => + { 'like' => $v->param('search') . '%' } + }, + ] + ) + : () + ), + }, { - 'sum' => 'sales.value', - '-as' => 'total_spend', + join => [ 'sales', 'organisation' ], + group_by => [ 'me.id', 'organisation.id' ], + '+select' => [ + { + 'sum' => 'sales.value', + '-as' => 'total_spend', + } + ], + '+as' => ['total_spend'], + page => $v->param('page') || 1, + rows => 10, + order_by => $order_by, } - ], - '+as' => [ 'total_spend' ], - page => $v->param('page') || 1, - rows => 10, - order_by => $order_by, - } - ); - - my @supplier_list = ( - map {{ - entity_id => $_->id, - name => $_->name, - street => $_->organisation->street_name, - town => $_->organisation->town, - postcode => $_->organisation->postcode, - country => $_->organisation->country, - spend => ($_->get_column('total_spend') / 100000) // 0, - }} $lcc_suppliers->all - ); - - return $c->render(json => { - success => Mojo::JSON->true, - suppliers => \@supplier_list, - page_no => $lcc_suppliers->pager->total_entries, - }); + ); + + my @supplier_list = ( + map { + { + entity_id => $_->id, + name => $_->name, + street => $_->organisation->street_name, + town => $_->organisation->town, + postcode => $_->organisation->postcode, + country => $_->organisation->country, + spend => ( $_->get_column('total_spend') / 100000 ) // 0, + } + } $lcc_suppliers->all + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + suppliers => \@supplier_list, + page_no => $lcc_suppliers->pager->total_entries, + } + ); } sub post_year_spend { - my $c = shift; + my $c = shift; - my $user = $c->stash->{api_user}; + my $user = $c->stash->{api_user}; - my $v = $c->validation; - $v->input($c->stash->{api_json}); - $v->required('from'); - $v->required('to'); + my $v = $c->validation; + $v->input( $c->stash->{api_json} ); + $v->required('from'); + $v->required('to'); - return $c->api_validation_error if $v->has_error; + return $c->api_validation_error if $v->has_error; - my $last = $c->parse_iso_date($v->param('to')); - my $first = $c->parse_iso_date($v->param('from')); + my $last = $c->parse_iso_date( $v->param('to') ); + my $first = $c->parse_iso_date( $v->param('from') ); - my $dtf = $c->schema->storage->datetime_parser; - my $driver = $c->schema->storage->dbh->{Driver}->{Name}; - my $spend_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( - { - purchase_time => { - -between => [ - $dtf->format_datetime($first), - $dtf->format_datetime($last), - ], - }, - buyer_id => $user->entity->id, - }, - { - columns => [ + my $dtf = $c->schema->storage->datetime_parser; + my $driver = $c->schema->storage->dbh->{Driver}->{Name}; + my $spend_rs = + $c->schema->resultset( 'ViewQuantisedTransaction' . $driver )->search( + { + purchase_time => { + -between => [ + $dtf->format_datetime($first), + $dtf->format_datetime($last), + ], + }, + buyer_id => $user->entity->id, + }, { - quantised => 'quantised_days', - count => \"COUNT(*)", - total_spend => { sum => 'value' }, + columns => [ + { + quantised => 'quantised_days', + count => \"COUNT(*)", + total_spend => { sum => 'value' }, + } + ], + group_by => 'quantised_days', + order_by => { '-asc' => 'quantised_days' }, } - ], - group_by => 'quantised_days', - order_by => { '-asc' => 'quantised_days' }, - } - ); - - my @graph_data = ( - map {{ - count => $_->get_column('count'), - value => ($_->get_column('total_spend') / 100000) // 0, - date => $_->get_column('quantised'), - }} $spend_rs->all, - ); - - return $c->render(json => { - success => Mojo::JSON->true, - data => \@graph_data, - }); + ); + + my @graph_data = ( + map { + { + count => $_->get_column('count'), + value => ( $_->get_column('total_spend') / 100000 ) // 0, + date => $_->get_column('quantised'), + } + } $spend_rs->all, + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + data => \@graph_data, + } + ); } sub post_supplier_count { - my $c = shift; + my $c = shift; - my $user = $c->stash->{api_user}; + my $user = $c->stash->{api_user}; - my $v = $c->validation; - $v->input($c->stash->{api_json}); - $v->required('from'); - $v->required('to'); + my $v = $c->validation; + $v->input( $c->stash->{api_json} ); + $v->required('from'); + $v->required('to'); - return $c->api_validation_error if $v->has_error; + return $c->api_validation_error if $v->has_error; - my $last = $c->parse_iso_date($v->param('to')); - my $first = $c->parse_iso_date($v->param('from')); + my $last = $c->parse_iso_date( $v->param('to') ); + my $first = $c->parse_iso_date( $v->param('from') ); - my $dtf = $c->schema->storage->datetime_parser; - my $driver = $c->schema->storage->dbh->{Driver}->{Name}; - my $spend_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( - { - purchase_time => { - -between => [ - $dtf->format_datetime($first), - $dtf->format_datetime($last), - ], - }, - buyer_id => $user->entity->id, - }, - { - join => { 'seller' => 'organisation' }, - select => [ - { count => 'me.value', '-as' => 'count' }, - { sum => 'me.value', '-as' => 'total_spend' }, - 'organisation.name', - 'me.quantised_days', - ], - as => [ qw/count total_spend name quantised_days/ ], - group_by => [ qw/me.quantised_days seller.id organisation.id/ ], - order_by => { '-asc' => 'me.quantised_days' }, - } - ); - - my @graph_data = ( - map {{ - count => $_->get_column('count'), - value => ($_->get_column('total_spend') / 100000) // 0, - date => $_->get_column('quantised_days'), - seller => $_->get_column('name'), - }} $spend_rs->all, - ); - - return $c->render(json => { - success => Mojo::JSON->true, - data => \@graph_data, - }); + my $dtf = $c->schema->storage->datetime_parser; + my $driver = $c->schema->storage->dbh->{Driver}->{Name}; + my $spend_rs = + $c->schema->resultset( 'ViewQuantisedTransaction' . $driver )->search( + { + purchase_time => { + -between => [ + $dtf->format_datetime($first), + $dtf->format_datetime($last), + ], + }, + buyer_id => $user->entity->id, + }, + { + join => { 'seller' => 'organisation' }, + select => [ + { count => 'me.value', '-as' => 'count' }, + { sum => 'me.value', '-as' => 'total_spend' }, + 'organisation.name', + 'me.quantised_days', + ], + as => [qw/count total_spend name quantised_days/], + group_by => [qw/me.quantised_days seller.id organisation.id/], + order_by => { '-asc' => 'me.quantised_days' }, + } + ); + + my @graph_data = ( + map { + { + count => $_->get_column('count'), + value => ( $_->get_column('total_spend') / 100000 ) // 0, + date => $_->get_column('quantised_days'), + seller => $_->get_column('name'), + } + } $spend_rs->all, + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + data => \@graph_data, + } + ); } sub post_supplier_history { - my $c = shift; - - my $user = $c->stash->{api_user}; - - # Temporary date lock for dev data - my $last = DateTime->new( - year => 2019, - month => 4, - day => 1 - ); - my $first = $last->clone->subtract(years => 1); - my $second = $last->clone->subtract(months => 6); - my $third = $last->clone->subtract(months => 3); - - my $dtf = $c->schema->storage->datetime_parser; - my $year_rs = $c->schema->resultset('Entity')->search( - { - 'sales.purchase_time' => { - -between => [ - $dtf->format_datetime($first), - $dtf->format_datetime($last), - ], - }, - 'sales.buyer_id' => $user->entity->id, - }, - { - join => [ 'sales', 'organisation' ], - columns => [ + my $c = shift; + + my $user = $c->stash->{api_user}; + + # Temporary date lock for dev data + my $last = DateTime->new( + year => 2019, + month => 4, + day => 1 + ); + my $first = $last->clone->subtract( years => 1 ); + my $second = $last->clone->subtract( months => 6 ); + my $third = $last->clone->subtract( months => 3 ); + + my $dtf = $c->schema->storage->datetime_parser; + my $year_rs = $c->schema->resultset('Entity')->search( + { + 'sales.purchase_time' => { + -between => [ + $dtf->format_datetime($first), + $dtf->format_datetime($last), + ], + }, + 'sales.buyer_id' => $user->entity->id, + }, { - id => 'me.id', - name => 'organisation.name', - count => \"COUNT(*)", - total_spend => { sum => 'sales.value' }, + join => [ 'sales', 'organisation' ], + columns => [ + { + id => 'me.id', + name => 'organisation.name', + count => \"COUNT(*)", + total_spend => { sum => 'sales.value' }, + } + ], + group_by => [ 'me.id', 'organisation.id' ], + order_by => { '-asc' => 'organisation.name' }, } - ], - group_by => [ 'me.id', 'organisation.id' ], - order_by => { '-asc' => 'organisation.name' }, - } - ); - my $half_year_rs = $c->schema->resultset('Entity')->search( - { - 'sales.purchase_time' => { - -between => [ - $dtf->format_datetime($second), - $dtf->format_datetime($last), - ], - }, - 'sales.buyer_id' => $user->entity->id, - }, - { - join => [ 'sales', 'organisation' ], - columns => [ + ); + my $half_year_rs = $c->schema->resultset('Entity')->search( + { + 'sales.purchase_time' => { + -between => [ + $dtf->format_datetime($second), + $dtf->format_datetime($last), + ], + }, + 'sales.buyer_id' => $user->entity->id, + }, { - id => 'me.id', - name => 'organisation.name', - count => \"COUNT(*)", - total_spend => { sum => 'sales.value' }, + join => [ 'sales', 'organisation' ], + columns => [ + { + id => 'me.id', + name => 'organisation.name', + count => \"COUNT(*)", + total_spend => { sum => 'sales.value' }, + } + ], + group_by => [ 'me.id', 'organisation.id' ], + order_by => { '-asc' => 'organisation.name' }, } - ], - group_by => [ 'me.id', 'organisation.id' ], - order_by => { '-asc' => 'organisation.name' }, - } - ); - my $quarter_year_rs = $c->schema->resultset('Entity')->search( - { - 'sales.purchase_time' => { - -between => [ - $dtf->format_datetime($third), - $dtf->format_datetime($last), - ], - }, - 'sales.buyer_id' => $user->entity->id, - }, - { - join => [ 'sales', 'organisation' ], - columns => [ + ); + my $quarter_year_rs = $c->schema->resultset('Entity')->search( { - id => 'me.id', - name => 'organisation.name', - count => \"COUNT(*)", - total_spend => { sum => 'sales.value' }, + 'sales.purchase_time' => { + -between => [ + $dtf->format_datetime($third), + $dtf->format_datetime($last), + ], + }, + 'sales.buyer_id' => $user->entity->id, + }, + { + join => [ 'sales', 'organisation' ], + columns => [ + { + id => 'me.id', + name => 'organisation.name', + count => \"COUNT(*)", + total_spend => { sum => 'sales.value' }, + } + ], + group_by => [ 'me.id', 'organisation.id' ], + order_by => { '-asc' => 'organisation.name' }, } - ], - group_by => [ 'me.id', 'organisation.id' ], - order_by => { '-asc' => 'organisation.name' }, + ); + + my %data; + for my $row ( $year_rs->all ) { + $data{ $row->get_column('id') } = { + id => $row->get_column('id'), + name => $row->get_column('name'), + quarter_count => 0, + quarter_total => 0, + half_count => 0, + half_total => 0, + year_count => $row->get_column('count'), + year_total => $row->get_column('total_spend') / 100000, + }; + } + + for my $row ( $half_year_rs->all ) { + $data{ $row->get_column('id') } = { + id => $row->get_column('id'), + name => $row->get_column('name'), + quarter_count => 0, + quarter_total => 0, + half_count => $row->get_column('count'), + half_total => $row->get_column('total_spend') / 100000, + year_count => 0, + year_total => 0, + %{ $data{ $row->get_column('id') } }, + }; } - ); - - my %data; - for my $row ($year_rs->all) { - $data{$row->get_column('id')} = { - id => $row->get_column('id'), - name => $row->get_column('name'), - quarter_count => 0, - quarter_total => 0, - half_count => 0, - half_total => 0, - year_count => $row->get_column('count'), - year_total => $row->get_column('total_spend') / 100000, - }; - } - - for my $row ($half_year_rs->all) { - $data{$row->get_column('id')} = { - id => $row->get_column('id'), - name => $row->get_column('name'), - quarter_count => 0, - quarter_total => 0, - half_count => $row->get_column('count'), - half_total => $row->get_column('total_spend') / 100000, - year_count => 0, - year_total => 0, - %{$data{$row->get_column('id')}}, - }; - } - - for my $row ($quarter_year_rs->all) { - $data{$row->get_column('id')} = { - id => $row->get_column('id'), - name => $row->get_column('name'), - quarter_count => $row->get_column('count'), - quarter_total => $row->get_column('total_spend') / 100000, - half_count => 0, - half_total => 0, - year_count => 0, - year_total => 0, - %{$data{$row->get_column('id')}}, - }; - } - - return $c->render(json => { - success => Mojo::JSON->true, - data => [ values %data ], - }); + + for my $row ( $quarter_year_rs->all ) { + $data{ $row->get_column('id') } = { + id => $row->get_column('id'), + name => $row->get_column('name'), + quarter_count => $row->get_column('count'), + quarter_total => $row->get_column('total_spend') / 100000, + half_count => 0, + half_total => 0, + year_count => 0, + year_total => 0, + %{ $data{ $row->get_column('id') } }, + }; + } + + return $c->render( + json => { + success => Mojo::JSON->true, + data => [ values %data ], + } + ); } sub post_lcc_table_summary { - my $c = shift; + my $c = shift; - my $user = $c->stash->{api_user}; + my $user = $c->stash->{api_user}; - my $v = $c->validation; - $v->input($c->stash->{api_json}); - $v->required('from'); - $v->required('to'); + my $v = $c->validation; + $v->input( $c->stash->{api_json} ); + $v->required('from'); + $v->required('to'); - return $c->api_validation_error if $v->has_error; + return $c->api_validation_error if $v->has_error; - my $last = $c->parse_iso_date($v->param('to')); - my $first = $c->parse_iso_date($v->param('from')); + my $last = $c->parse_iso_date( $v->param('to') ); + my $first = $c->parse_iso_date( $v->param('from') ); - my $transaction_rs = $c->schema->resultset('Transaction'); + my $transaction_rs = $c->schema->resultset('Transaction'); - my $dtf = $c->schema->storage->datetime_parser; - my $ward_transactions_rs = $transaction_rs->search( - { - purchase_time => { - -between => [ - $dtf->format_datetime($first), - $dtf->format_datetime($last), - ], - }, - buyer_id => $user->entity->id, - }, - { - join => { seller => { postcode => { gb_postcode => 'ward' } } }, - group_by => 'ward.id', - select => [ - { count => 'me.id', '-as' => 'count' }, - { sum => 'me.value', '-as' => 'sum' }, - 'ward.ward' - ], - as => [ qw/count sum ward_name/ ], - } - ); - - my $transaction_type_data = {}; - - my %meta_names = ( - local_service => "Local Services", - regional_service => "Regional Services", - national_service => "National Services", - private_household_rebate => "Private Household Rebates etc", - business_tax_and_rebate => "Business Tax & Service Rebates", - stat_loc_gov => "Statutory Loc Gov", - central_loc_gov => "Central Gov HMRC", - ); - - for my $meta (qw/ - local_service - regional_service - national_service - private_household_rebate - business_tax_and_rebate - stat_loc_gov - central_loc_gov - /) { - my $transaction_type_rs = $transaction_rs->search( - { - 'me.purchase_time' => { - -between => [ - $dtf->format_datetime($first), - $dtf->format_datetime($last), - ], + my $dtf = $c->schema->storage->datetime_parser; + my $ward_transactions_rs = $transaction_rs->search( + { + purchase_time => { + -between => [ + $dtf->format_datetime($first), + $dtf->format_datetime($last), + ], + }, + buyer_id => $user->entity->id, }, - 'me.buyer_id' => $user->entity->id, - 'meta.' . $meta => 1, - }, - { - join => 'meta', - group_by => 'meta.' . $meta, - select => [ - { count => 'me.id', '-as' => 'count' }, - { sum => 'me.value', '-as' => 'sum' }, - ], - as => [ qw/count sum/ ], - } - )->first; - - $transaction_type_data->{$meta} = { - ($transaction_type_rs ? ( - count => $transaction_type_rs->get_column('count'), - sum => $transaction_type_rs->get_column('sum'), - type => $meta_names{$meta}, - ) : ( - count => 0, - sum => 0, - type => $meta_names{$meta}, - )), + { + join => { seller => { postcode => { gb_postcode => 'ward' } } }, + group_by => 'ward.id', + select => [ + { count => 'me.id', '-as' => 'count' }, + { sum => 'me.value', '-as' => 'sum' }, + 'ward.ward' + ], + as => [qw/count sum ward_name/], + } + ); + + my $transaction_type_data = {}; + + my %meta_names = ( + local_service => "Local Services", + regional_service => "Regional Services", + national_service => "National Services", + private_household_rebate => "Private Household Rebates etc", + business_tax_and_rebate => "Business Tax & Service Rebates", + stat_loc_gov => "Statutory Loc Gov", + central_loc_gov => "Central Gov HMRC", + ); + + for my $meta ( + qw/ + local_service + regional_service + national_service + private_household_rebate + business_tax_and_rebate + stat_loc_gov + central_loc_gov + / + ) + { + my $transaction_type_rs = $transaction_rs->search( + { + 'me.purchase_time' => { + -between => [ + $dtf->format_datetime($first), + $dtf->format_datetime($last), + ], + }, + 'me.buyer_id' => $user->entity->id, + 'meta.' . $meta => 1, + }, + { + join => 'meta', + group_by => 'meta.' . $meta, + select => [ + { count => 'me.id', '-as' => 'count' }, + { sum => 'me.value', '-as' => 'sum' }, + ], + as => [qw/count sum/], + } + )->first; + + $transaction_type_data->{$meta} = { + ( + $transaction_type_rs + ? ( + count => $transaction_type_rs->get_column('count'), + sum => $transaction_type_rs->get_column('sum'), + type => $meta_names{$meta}, + ) + : ( + count => 0, + sum => 0, + type => $meta_names{$meta}, + ) + ), + }; } - } - - my @ward_transaction_list = ( - map {{ - ward => $_->get_column('ward_name') || "N/A", - sum => $_->get_column('sum') / 100000, - count => $_->get_column('count'), - }} $ward_transactions_rs->all - ); - - return $c->render(json => { - success => Mojo::JSON->true, - wards => \@ward_transaction_list, - types => $transaction_type_data, - }); + + my @ward_transaction_list = ( + map { + { + ward => $_->get_column('ward_name') || "N/A", + sum => $_->get_column('sum') / 100000, + count => $_->get_column('count'), + } + } $ward_transactions_rs->all + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + wards => \@ward_transaction_list, + types => $transaction_type_data, + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm index d5e4bfa..137a0fa 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm @@ -2,61 +2,75 @@ package Pear::LocalLoop::Controller::Api::Feedback; use Mojo::Base 'Mojolicious::Controller'; has error_messages => sub { - return { - email => { - required => { message => 'Email is required or not registered', status => 400 }, - in_resultset => { message => 'Email is required or not registered', status => 400, error => "required" }, - }, - feedbacktext => { - required => { message => 'Feedback is required', status => 400 }, - }, - app_name => { - required => { message => 'App Name is required', status => 400 }, - }, - package_name => { - required => { message => 'Package Name is required', status => 400 }, - }, - version_code => { - required => { message => 'Version Code is required', status => 400 }, - }, - version_number => { - required => { message => 'Version Number is required', status => 400 }, - }, - }; + return { + email => { + required => { + message => 'Email is required or not registered', + status => 400 + }, + in_resultset => { + message => 'Email is required or not registered', + status => 400, + error => "required" + }, + }, + feedbacktext => { + required => { message => 'Feedback is required', status => 400 }, + }, + app_name => { + required => { message => 'App Name is required', status => 400 }, + }, + package_name => { + required => + { message => 'Package Name is required', status => 400 }, + }, + version_code => { + required => + { message => 'Version Code is required', status => 400 }, + }, + version_number => { + required => + { message => 'Version Number is required', status => 400 }, + }, + }; }; sub post_feedback { - my $c = shift; + my $c = shift; - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); - my $user_rs = $c->schema->resultset('User'); + my $user_rs = $c->schema->resultset('User'); - $validation->required('email')->in_resultset( 'email', $user_rs ); - $validation->required('feedbacktext', 'not_empty'); - $validation->required('app_name'); - $validation->required('package_name'); - $validation->required('version_code'); - $validation->required('version_number'); + $validation->required('email')->in_resultset( 'email', $user_rs ); + $validation->required( 'feedbacktext', 'not_empty' ); + $validation->required('app_name'); + $validation->required('package_name'); + $validation->required('version_code'); + $validation->required('version_number'); - return $c->api_validation_error if $validation->has_error; + return $c->api_validation_error if $validation->has_error; - my $user = $user_rs->find({'email' => $validation->param('email')}); + my $user = $user_rs->find( { 'email' => $validation->param('email') } ); - $c->schema->resultset('Feedback')->create({ - user => $user, - feedbacktext => $validation->param('feedbacktext'), - app_name => $validation->param('app_name'), - package_name => $validation->param('package_name'), - version_code => $validation->param('version_code'), - version_number => $validation->param('version_number'), - }); + $c->schema->resultset('Feedback')->create( + { + user => $user, + feedbacktext => $validation->param('feedbacktext'), + app_name => $validation->param('app_name'), + package_name => $validation->param('package_name'), + version_code => $validation->param('version_code'), + version_number => $validation->param('version_number'), + } + ); - return $c->render( json => { - success => Mojo::JSON->true, - message => 'Thank you for your Feedback!', - }); + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Thank you for your Feedback!', + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm index aaabb8a..dd4c7b9 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm @@ -3,160 +3,188 @@ use Mojo::Base 'Mojolicious::Controller'; use Mojo::JSON; has error_messages => sub { - return { - entry_period => { - required => { message => 'No entry period sent.', status => 400 }, - }, - employee_amount => { - required => { message => 'No employee amount sent.', status => 400 }, - }, - local_employee_amount => { - required => { message => 'No local employee amount sent.', status => 400 }, - }, - gross_payroll => { - required => { message => 'No gross payroll sent.', status => 400 }, - }, - payroll_income_tax => { - required => { message => 'No total income tax sent.', status => 400 }, - }, - payroll_employee_ni => { - required => { message => 'No total employee NI sent.', status => 400 }, - }, - payroll_employer_ni => { - required => { message => 'No total employer NI sent.', status => 400 }, - }, - payroll_total_pension => { - required => { message => 'No total total pension sent.', status => 400 }, - }, - payroll_other_benefit => { - required => { message => 'No total other benefits total sent.', status => 400 }, - }, - supplier_business_name => { - required => { message => 'No supplier business name sent.', status => 400 }, - }, - postcode => { - required => { message => 'No postcode sent.', status => 400 }, - postcode => { message => 'postcode must be valid', status => 400 }, - }, - monthly_spend => { - required => { message => 'No monthly spend sent.', status => 400 }, - }, - employee_no => { - required => { message => 'No employee no sent.', status => 400 }, - }, - employee_income_tax => { - required => { message => 'No employee income tax sent.', status => 400 }, - }, - employee_gross_wage => { - required => { message => 'No employee gross wage sent.', status => 400 }, - }, - employee_ni => { - required => { message => 'No employee ni sent.', status => 400 }, - }, - employee_pension => { - required => { message => 'No employee pension sent.', status => 400 }, - }, - employee_other_benefit => { - required => { message => 'No employee other benefits sent.', status => 400 }, - }, - }; + return { + entry_period => { + required => { message => 'No entry period sent.', status => 400 }, + }, + employee_amount => { + required => + { message => 'No employee amount sent.', status => 400 }, + }, + local_employee_amount => { + required => + { message => 'No local employee amount sent.', status => 400 }, + }, + gross_payroll => { + required => { message => 'No gross payroll sent.', status => 400 }, + }, + payroll_income_tax => { + required => + { message => 'No total income tax sent.', status => 400 }, + }, + payroll_employee_ni => { + required => + { message => 'No total employee NI sent.', status => 400 }, + }, + payroll_employer_ni => { + required => + { message => 'No total employer NI sent.', status => 400 }, + }, + payroll_total_pension => { + required => + { message => 'No total total pension sent.', status => 400 }, + }, + payroll_other_benefit => { + required => { + message => 'No total other benefits total sent.', + status => 400 + }, + }, + supplier_business_name => { + required => + { message => 'No supplier business name sent.', status => 400 }, + }, + postcode => { + required => { message => 'No postcode sent.', status => 400 }, + postcode => { message => 'postcode must be valid', status => 400 }, + }, + monthly_spend => { + required => { message => 'No monthly spend sent.', status => 400 }, + }, + employee_no => { + required => { message => 'No employee no sent.', status => 400 }, + }, + employee_income_tax => { + required => + { message => 'No employee income tax sent.', status => 400 }, + }, + employee_gross_wage => { + required => + { message => 'No employee gross wage sent.', status => 400 }, + }, + employee_ni => { + required => { message => 'No employee ni sent.', status => 400 }, + }, + employee_pension => { + required => + { message => 'No employee pension sent.', status => 400 }, + }, + employee_other_benefit => { + required => + { message => 'No employee other benefits sent.', status => 400 }, + }, + }; }; sub post_payroll_read { - my $c = shift; - - my $user = $c->stash->{api_user}; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - $validation->optional('page')->number; - - return $c->api_validation_error if $validation->has_error; - - my $payrolls = $user->entity->organisation->payroll->search( - undef, { - page => $validation->param('page') || 1, - rows => 10, - order_by => { -desc => 'submitted_at' }, - }, - ); - -# purchase_time needs timezone attached to it - my @payroll_list = ( - map {{ - entry_period => $_->entry_period, - employee_amount => $_->employee_amount, - local_employee_amount => $_->local_employee_amount, - gross_payroll => $_->gross_payroll / 100000, - payroll_income_tax => $_->payroll_income_tax / 100000, - payroll_employee_ni => $_->payroll_employee_ni / 100000, - payroll_employer_ni => $_->payroll_employer_ni / 100000, - payroll_total_pension => $_->payroll_total_pension / 100000, - payroll_other_benefit => $_->payroll_other_benefit / 100000, - }} $payrolls->all - ); - - return $c->render( json => { - success => Mojo::JSON->true, - payrolls => \@payroll_list, - page_no => $payrolls->pager->total_entries, - }); + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->optional('page')->number; + + return $c->api_validation_error if $validation->has_error; + + my $payrolls = $user->entity->organisation->payroll->search( + undef, + { + page => $validation->param('page') || 1, + rows => 10, + order_by => { -desc => 'submitted_at' }, + }, + ); + + # purchase_time needs timezone attached to it + my @payroll_list = ( + map { + { + entry_period => $_->entry_period, + employee_amount => $_->employee_amount, + local_employee_amount => $_->local_employee_amount, + gross_payroll => $_->gross_payroll / 100000, + payroll_income_tax => $_->payroll_income_tax / 100000, + payroll_employee_ni => $_->payroll_employee_ni / 100000, + payroll_employer_ni => $_->payroll_employer_ni / 100000, + payroll_total_pension => $_->payroll_total_pension / 100000, + payroll_other_benefit => $_->payroll_other_benefit / 100000, + } + } $payrolls->all + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + payrolls => \@payroll_list, + page_no => $payrolls->pager->total_entries, + } + ); } sub post_payroll_add { - my $c = shift; - - my $user = $c->stash->{api_user}; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - - return $c->api_validation_error if $validation->has_error; - - my $user_rs = $c->schema->resultset('User')->search({ - id => { "!=" => $user->id }, - }); - - $validation->required('entry_period'); - $validation->required('employee_amount'); - $validation->required('local_employee_amount'); - $validation->required('gross_payroll'); - $validation->required('payroll_income_tax'); - $validation->required('payroll_employee_ni'); - $validation->required('payroll_employer_ni'); - $validation->required('payroll_total_pension'); - $validation->required('payroll_other_benefit'); - - return $c->api_validation_error if $validation->has_error; - - my $entry_period = $c->parse_iso_month($validation->param('entry_period')); - my $employee_amount = $validation->param('employee_amount'); - my $local_employee_amount = $validation->param('local_employee_amount'); - my $gross_payroll = $validation->param('gross_payroll'); - my $payroll_income_tax = $validation->param('payroll_income_tax'); - my $payroll_employee_ni = $validation->param('payroll_employee_ni'); - my $payroll_employer_ni = $validation->param('payroll_employer_ni'); - my $payroll_total_pension = $validation->param('payroll_total_pension'); - my $payroll_other_benefit = $validation->param('payroll_other_benefit'); - - $c->schema->txn_do( sub { - $user->entity->organisation->payroll->create({ - entry_period => $entry_period, - employee_amount => $employee_amount, - local_employee_amount => $local_employee_amount, - gross_payroll => $gross_payroll * 100000, - payroll_income_tax => $payroll_income_tax * 100000, - payroll_employee_ni => $payroll_employee_ni * 100000, - payroll_employer_ni => $payroll_employer_ni * 100000, - payroll_total_pension => $payroll_total_pension * 100000, - payroll_other_benefit => $payroll_other_benefit * 100000, - }); - }); - - return $c->render( json => { - success => Mojo::JSON->true, - message => 'Submitted Payroll Info Successfully', - }); + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + return $c->api_validation_error if $validation->has_error; + + my $user_rs = $c->schema->resultset('User')->search( + { + id => { "!=" => $user->id }, + } + ); + + $validation->required('entry_period'); + $validation->required('employee_amount'); + $validation->required('local_employee_amount'); + $validation->required('gross_payroll'); + $validation->required('payroll_income_tax'); + $validation->required('payroll_employee_ni'); + $validation->required('payroll_employer_ni'); + $validation->required('payroll_total_pension'); + $validation->required('payroll_other_benefit'); + + return $c->api_validation_error if $validation->has_error; + + my $entry_period = + $c->parse_iso_month( $validation->param('entry_period') ); + my $employee_amount = $validation->param('employee_amount'); + my $local_employee_amount = $validation->param('local_employee_amount'); + my $gross_payroll = $validation->param('gross_payroll'); + my $payroll_income_tax = $validation->param('payroll_income_tax'); + my $payroll_employee_ni = $validation->param('payroll_employee_ni'); + my $payroll_employer_ni = $validation->param('payroll_employer_ni'); + my $payroll_total_pension = $validation->param('payroll_total_pension'); + my $payroll_other_benefit = $validation->param('payroll_other_benefit'); + + $c->schema->txn_do( + sub { + $user->entity->organisation->payroll->create( + { + entry_period => $entry_period, + employee_amount => $employee_amount, + local_employee_amount => $local_employee_amount, + gross_payroll => $gross_payroll * 100000, + payroll_income_tax => $payroll_income_tax * 100000, + payroll_employee_ni => $payroll_employee_ni * 100000, + payroll_employer_ni => $payroll_employer_ni * 100000, + payroll_total_pension => $payroll_total_pension * 100000, + payroll_other_benefit => $payroll_other_benefit * 100000, + } + ); + } + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Submitted Payroll Info Successfully', + } + ); } sub post_supplier_read { @@ -164,36 +192,44 @@ sub post_supplier_read { } sub post_supplier_add { - my $c = shift; - - my $user = $c->stash->{api_user}; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - - return $c->api_validation_error if $validation->has_error; - - my $user_rs = $c->schema->resultset('User')->search({ - id => { "!=" => $user->id }, - }); - - $validation->required('entry_period'); - $validation->required('postcode')->postcode; - $validation->required('supplier_business_name'); - $validation->required('monthly_spend'); - - return $c->api_validation_error if $validation->has_error; - - $c->schema->txn_do( sub { - $user->entity->organisation->update({ - entry_period => $validation->param('entry_period'), - }); - }); - - return $c->render( json => { - success => Mojo::JSON->true, - message => 'Submitted Supplier Info Successfully', - }); + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + return $c->api_validation_error if $validation->has_error; + + my $user_rs = $c->schema->resultset('User')->search( + { + id => { "!=" => $user->id }, + } + ); + + $validation->required('entry_period'); + $validation->required('postcode')->postcode; + $validation->required('supplier_business_name'); + $validation->required('monthly_spend'); + + return $c->api_validation_error if $validation->has_error; + + $c->schema->txn_do( + sub { + $user->entity->organisation->update( + { + entry_period => $validation->param('entry_period'), + } + ); + } + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Submitted Supplier Info Successfully', + } + ); } sub post_employee_read { @@ -201,39 +237,47 @@ sub post_employee_read { } sub post_employee_add { - my $c = shift; - - my $user = $c->stash->{api_user}; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - - return $c->api_validation_error if $validation->has_error; - - my $user_rs = $c->schema->resultset('User')->search({ - id => { "!=" => $user->id }, - }); - - $validation->required('entry_period'); - $validation->required('employee_no'); - $validation->required('employee_income_tax'); - $validation->required('employee_gross_wage'); - $validation->required('employee_ni'); - $validation->required('employee_pension'); - $validation->required('employee_other_benefit'); - - return $c->api_validation_error if $validation->has_error; - - $c->schema->txn_do( sub { - $user->entity->organisation->update({ - entry_period => $validation->param('entry_period'), - }); - }); - - return $c->render( json => { - success => Mojo::JSON->true, - message => 'Submitted Employee Info Successfully', - }); + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + return $c->api_validation_error if $validation->has_error; + + my $user_rs = $c->schema->resultset('User')->search( + { + id => { "!=" => $user->id }, + } + ); + + $validation->required('entry_period'); + $validation->required('employee_no'); + $validation->required('employee_income_tax'); + $validation->required('employee_gross_wage'); + $validation->required('employee_ni'); + $validation->required('employee_pension'); + $validation->required('employee_other_benefit'); + + return $c->api_validation_error if $validation->has_error; + + $c->schema->txn_do( + sub { + $user->entity->organisation->update( + { + entry_period => $validation->param('entry_period'), + } + ); + } + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Submitted Employee Info Successfully', + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/Register.pm b/lib/Pear/LocalLoop/Controller/Api/Register.pm index aee6b80..8a4abd4 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Register.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Register.pm @@ -5,142 +5,175 @@ use DateTime; use Geo::UK::Postcode::Regex; has error_messages => sub { - return { - token => { - required => { message => 'No token sent.', status => 400 }, - in_resultset => { message => 'Token invalid or has been used.', status => 401 }, - }, - name => { - required => { message => 'No organisation name sent or was blank.', status => 400 }, - }, - display_name => { - required => { message => 'No display name sent or was blank.', status => 400 }, - }, - full_name => { - required => { message => 'No full name sent or was blank.', status => 400 }, - }, - email => { - required => { message => 'No email sent.', status => 400 }, - email => { message => 'Email is invalid.', status => 400 }, - not_in_resultset => { message => 'Email already in use.', status => 403 }, - }, - postcode => { - required => { message => 'No postcode sent.', status => 400 }, - postcode => { message => 'Postcode is invalid', status => 400 }, - }, - password => { - required => { message => 'No password sent.', status => 400 }, - }, - usertype => { - required => { message => 'No usertype sent.', status => 400 }, - in => { message => '"usertype" is invalid.', status => 400 }, - }, - year_of_birth => { - required => { message => 'No year of birth sent.', status => 400 }, - number => { message => 'year of birth is invalid', status => 400 }, - gt_num => { message => 'year of birth must be within last 150 years', status => 400 }, - lt_num => { message => 'year of birth must be atleast 10 years ago', status => 400 }, - }, - street_name => { - required => { message => 'No street name sent.', status => 400 }, - }, - town => { - required => { message => 'No town/city sent.', status => 400 }, - }, - }; -}; - -sub post_register { - my $c = shift; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - - my $token_rs = $c->schema->resultset('AccountToken')->search_rs({used => 0}); - $validation->required('token')->in_resultset('name', $token_rs); - - my $user_rs = $c->schema->resultset('User'); - $validation->required('email')->email->not_in_resultset('email', $user_rs); - $validation->required('password'); - - $validation->required('postcode')->postcode; - $validation->required('usertype')->in('customer', 'organisation'); - - my $usertype = $validation->param('usertype') || ''; - - if ( $usertype eq 'customer' ) { - $validation->required('display_name', 'not_empty'); - $validation->required('full_name', 'not_empty'); - my $year = DateTime->now->year; - $validation->required('year_of_birth')->number->gt_num($year - 150)->lt_num($year - 10); - } elsif ( $usertype eq 'organisation' ) { - $validation->required('name'); - $validation->required('street_name'); - $validation->required('town'); - $validation->required('sector'); - } - - return $c->api_validation_error if $validation->has_error; - - my $location = $c->get_location_from_postcode( - $validation->param('postcode'), - $usertype, - ); - - if ($usertype eq 'customer'){ - - $c->schema->txn_do( sub { - $c->schema->resultset('AccountToken')->find({ - name => $validation->param('token'), - used => 0, - })->update({ used => 1 }); - - $c->schema->resultset('Entity')->create({ - customer => { - full_name => $validation->param('full_name'), - display_name => $validation->param('display_name'), - year_of_birth => $validation->param('year_of_birth'), - postcode => $validation->param('postcode'), - ( defined $location ? ( %$location ) : () ), + return { + token => { + required => { message => 'No token sent.', status => 400 }, + in_resultset => + { message => 'Token invalid or has been used.', status => 401 }, + }, + name => { + required => { + message => 'No organisation name sent or was blank.', + status => 400 + }, + }, + display_name => { + required => { + message => 'No display name sent or was blank.', + status => 400 + }, + }, + full_name => { + required => + { message => 'No full name sent or was blank.', status => 400 }, + }, + email => { + required => { message => 'No email sent.', status => 400 }, + email => { message => 'Email is invalid.', status => 400 }, + not_in_resultset => + { message => 'Email already in use.', status => 403 }, }, - user => { - email => $validation->param('email'), - password => $validation->param('password'), + postcode => { + required => { message => 'No postcode sent.', status => 400 }, + postcode => { message => 'Postcode is invalid', status => 400 }, }, - type => 'customer', - }); - }); - - } - elsif ($usertype eq 'organisation') { - - $c->schema->txn_do( sub { - $c->schema->resultset('AccountToken')->find({ - name => $validation->param('token'), - used => 0, - })->update({ used => 1 }); - $c->schema->resultset('Entity')->create({ - organisation => { - name => $validation->param('name'), - street_name => $validation->param('street_name'), - town => $validation->param('town'), - sector => $validation->param('sector'), - postcode => $validation->param('postcode'), - ( defined $location ? ( %$location ) : () ), + password => { + required => { message => 'No password sent.', status => 400 }, }, - user => { - email => $validation->param('email'), - password => $validation->param('password'), + usertype => { + required => { message => 'No usertype sent.', status => 400 }, + in => { message => '"usertype" is invalid.', status => 400 }, }, - type => 'organisation', - }); - }); - } - - return $c->render( json => { - success => Mojo::JSON->true, - message => 'Registered Successfully', - }); + year_of_birth => { + required => { message => 'No year of birth sent.', status => 400 }, + number => { message => 'year of birth is invalid', status => 400 }, + gt_num => { + message => 'year of birth must be within last 150 years', + status => 400 + }, + lt_num => { + message => 'year of birth must be atleast 10 years ago', + status => 400 + }, + }, + street_name => { + required => { message => 'No street name sent.', status => 400 }, + }, + town => { + required => { message => 'No town/city sent.', status => 400 }, + }, + }; +}; + +sub post_register { + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + my $token_rs = + $c->schema->resultset('AccountToken')->search_rs( { used => 0 } ); + $validation->required('token')->in_resultset( 'name', $token_rs ); + + my $user_rs = $c->schema->resultset('User'); + $validation->required('email') + ->email->not_in_resultset( 'email', $user_rs ); + $validation->required('password'); + + $validation->required('postcode')->postcode; + $validation->required('usertype')->in( 'customer', 'organisation' ); + + my $usertype = $validation->param('usertype') || ''; + + if ( $usertype eq 'customer' ) { + $validation->required( 'display_name', 'not_empty' ); + $validation->required( 'full_name', 'not_empty' ); + my $year = DateTime->now->year; + $validation->required('year_of_birth')->number->gt_num( $year - 150 ) + ->lt_num( $year - 10 ); + } + elsif ( $usertype eq 'organisation' ) { + $validation->required('name'); + $validation->required('street_name'); + $validation->required('town'); + $validation->required('sector'); + } + + return $c->api_validation_error if $validation->has_error; + + my $location = + $c->get_location_from_postcode( $validation->param('postcode'), + $usertype, ); + + if ( $usertype eq 'customer' ) { + + $c->schema->txn_do( + sub { + $c->schema->resultset('AccountToken')->find( + { + name => $validation->param('token'), + used => 0, + } + )->update( { used => 1 } ); + + $c->schema->resultset('Entity')->create( + { + customer => { + full_name => $validation->param('full_name'), + display_name => $validation->param('display_name'), + year_of_birth => + $validation->param('year_of_birth'), + postcode => $validation->param('postcode'), + ( defined $location ? (%$location) : () ), + }, + user => { + email => $validation->param('email'), + password => $validation->param('password'), + }, + type => 'customer', + } + ); + } + ); + + } + elsif ( $usertype eq 'organisation' ) { + + $c->schema->txn_do( + sub { + $c->schema->resultset('AccountToken')->find( + { + name => $validation->param('token'), + used => 0, + } + )->update( { used => 1 } ); + $c->schema->resultset('Entity')->create( + { + organisation => { + name => $validation->param('name'), + street_name => $validation->param('street_name'), + town => $validation->param('town'), + sector => $validation->param('sector'), + postcode => $validation->param('postcode'), + ( defined $location ? (%$location) : () ), + }, + user => { + email => $validation->param('email'), + password => $validation->param('password'), + }, + type => 'organisation', + } + ); + } + ); + } + + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Registered Successfully', + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm index e518b78..399360e 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm @@ -8,22 +8,23 @@ use Mojo::File; use Carp; has error_messages => sub { - return { - #devicetokens => { - # required => { message => 'Device token is required', status => 400 }, - # in_resultset => { message => 'Device token not found', status => 400 }, - #}, - topic => { - required => { message => 'Topic is required', status => 400 }, - }, - sender => { - required => { message => 'Sender name is required', status => 400 }, - in_resultset => { message => 'Sender org not found', status => 400 }, - }, - messagetext => { - required => { message => 'Message is required', status => 400 }, - }, - }; + return { + #devicetokens => { + # required => { message => 'Device token is required', status => 400 }, + # in_resultset => { message => 'Device token not found', status => 400 }, + #}, + topic => { + required => { message => 'Topic is required', status => 400 }, + }, + sender => { + required => { message => 'Sender name is required', status => 400 }, + in_resultset => + { message => 'Sender org not found', status => 400 }, + }, + messagetext => { + required => { message => 'Message is required', status => 400 }, + }, + }; }; =begin comment @@ -33,120 +34,135 @@ has error_messages => sub { https://stackoverflow.com/q/56556438/4580273 =cut -my $jwt = create_jwt_from_path_and_scopes('./localspend-47012.json', 'email https://www.googleapis.com/auth/cloud-platform'); +my $jwt = create_jwt_from_path_and_scopes( './localspend-47012.json', + 'email https://www.googleapis.com/auth/cloud-platform' ); my $ua = LWP::UserAgent->new(); -my $response = $ua->post('https://www.googleapis.com/oauth2/v4/token', - { - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', - 'assertion' => $jwt - } +my $response = $ua->post( + 'https://www.googleapis.com/oauth2/v4/token', + { + 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', + 'assertion' => $jwt + } ); -my $bearer_token = parse_json($response->content); - -sub create_jwt_from_path_and_scopes -{ - my ( $path, $scope ) = @_; - croak("No path provided") if not defined $path; - croak("$path not available") if not -f $path; - my $json = decode_json( Mojo::File->new($path)->slurp ); - croak("No Private key in $path") if not defined $json->{private_key}; - croak("Not a service account") if $json->{type} ne 'service_account'; - my $jwt = Mojo::JWT->new(); - $jwt->algorithm('RS256'); - $jwt->secret($json->{private_key}); - - $jwt->claims( { - iss => $json->{client_email}, - scope => $scope, - aud => 'https://www.googleapis.com/oauth2/v4/token', - iat => time(), - exp => time()+3600 - } ); - $jwt->set_iat( 1 ); - return $jwt->encode; +my $bearer_token = parse_json( $response->content ); + +sub create_jwt_from_path_and_scopes { + my ( $path, $scope ) = @_; + croak("No path provided") if not defined $path; + croak("$path not available") if not -f $path; + my $json = decode_json( Mojo::File->new($path)->slurp ); + croak("No Private key in $path") if not defined $json->{private_key}; + croak("Not a service account") if $json->{type} ne 'service_account'; + my $jwt = Mojo::JWT->new(); + $jwt->algorithm('RS256'); + $jwt->secret( $json->{private_key} ); + + $jwt->claims( + { + iss => $json->{client_email}, + scope => $scope, + aud => 'https://www.googleapis.com/oauth2/v4/token', + iat => time(), + exp => time() + 3600 + } + ); + $jwt->set_iat(1); + return $jwt->encode; } sub get_topics { - my $c = shift; - - my $topic_rs = $c->schema->resultset('Topic'); - - my @topics = ( - map {{ - id => $_->id, - name => $_->name, - numberOfSubscribers => $_->search_related('device_subscriptions', {'topic_id' => $_->id})->count, - }} $topic_rs->all - ); - - return $c->render( json => { - success => Mojo::JSON->true, - topics => \@topics, - }); + my $c = shift; + + my $topic_rs = $c->schema->resultset('Topic'); + + my @topics = ( + map { + { + id => $_->id, + name => $_->name, + numberOfSubscribers => + $_->search_related( 'device_subscriptions', + { 'topic_id' => $_->id } )->count, + } + } $topic_rs->all + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + topics => \@topics, + } + ); } sub post_message { - my $c = shift; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - - #$validation->required('devicetokens')->in_resultset('token', $c->schema->resultset('DeviceToken')); - $validation->required('topic'); - $validation->required('sender')->in_resultset('name', $c->schema->resultset('Organisation')); - $validation->required('messagetext'); - - return $c->api_validation_error if $validation->has_error; - - my $end_point = "https://fcm.googleapis.com/v1/projects/localspend-47012/messages:send"; - - my $request = HTTP::Request->new('POST', $end_point); - $request->header('Authorization' => "Bearer $bearer_token->{access_token}"); - $request->header('Content-Type' => 'application/json'); - - $request->content(JSON::encode_json ({ - message => { - topic => $validation->param('topic'), - notification => { - title => $validation->param('sender'), - body => $validation->param('messagetext') - }, - webpush => { - headers => { - urgency => 'very-low' - }, - notification => { - title => $validation->param('sender'), - body => $validation->param('messagetext'), - } - } - } - })); + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + +#$validation->required('devicetokens')->in_resultset('token', $c->schema->resultset('DeviceToken')); + $validation->required('topic'); + $validation->required('sender') + ->in_resultset( 'name', $c->schema->resultset('Organisation') ); + $validation->required('messagetext'); + + return $c->api_validation_error if $validation->has_error; + + my $end_point = + "https://fcm.googleapis.com/v1/projects/localspend-47012/messages:send"; + + my $request = HTTP::Request->new( 'POST', $end_point ); + $request->header( + 'Authorization' => "Bearer $bearer_token->{access_token}" ); + $request->header( 'Content-Type' => 'application/json' ); + + $request->content( + JSON::encode_json( + { + message => { + topic => $validation->param('topic'), + notification => { + title => $validation->param('sender'), + body => $validation->param('messagetext') + }, + webpush => { + headers => { + urgency => 'very-low' + }, + notification => { + title => $validation->param('sender'), + body => $validation->param('messagetext'), + } + } + } + } + ) + ); - my $response = $ua->request($request); + my $response = $ua->request($request); - if ($response->is_success) { - return $c->render( json => { - success => Mojo::JSON->true, - message => 'Your message has been sent successfully!', - }); - } elsif ($response->is_error) { - return $c->render( - json => { - success => Mojo::JSON->false, - message => [ - $response->decoded_content, - $jwt, - $bearer_token - ], - error => 'message_error', - }, - status => $response->code, - ); - } + if ( $response->is_success ) { + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Your message has been sent successfully!', + } + ); + } + elsif ( $response->is_error ) { + return $c->render( + json => { + success => Mojo::JSON->false, + message => [ $response->decoded_content, $jwt, $bearer_token ], + error => 'message_error', + }, + status => $response->code, + ); + } } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index d9d127c..25278fb 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -4,509 +4,586 @@ use Mojo::Base 'Mojolicious::Controller'; use List::Util qw/ max sum /; has error_messages => sub { - return { - type => { - required => { message => 'Type of Leaderboard Required', status => 400 }, - in_resultset => { message => 'Unrecognised Leaderboard Type', status => 400 }, - }, - }; + return { + type => { + required => + { message => 'Type of Leaderboard Required', status => 400 }, + in_resultset => + { message => 'Unrecognised Leaderboard Type', status => 400 }, + }, + }; }; sub post_index { - my $c = shift; - - my $user = $c->stash->{api_user}->entity; - - my $today_rs = $user->purchases->today_rs; - my $today_sum = $today_rs->get_column('value')->sum || 0; - my $today_count = $today_rs->count; - - my $week_rs = $user->purchases->week_rs; - my $week_sum = $week_rs->get_column('value')->sum || 0; - my $week_count = $week_rs->count; - - my $month_rs = $user->purchases->month_rs; - my $month_sum = $month_rs->get_column('value')->sum || 0; - my $month_count = $month_rs->count; - - my $user_rs = $user->purchases; - my $user_sum = $user_rs->get_column('value')->sum || 0; - my $user_count = $user_rs->count; - - my $global_rs = $c->schema->resultset('Transaction'); - my $global_sum = $global_rs->get_column('value')->sum || 0; - my $global_count = $global_rs->count; - - my $leaderboard_rs = $c->schema->resultset('Leaderboard'); - my $monthly_board = $leaderboard_rs->get_latest( 'monthly_total' ); - my $monthly_values = $monthly_board->values; - my $current_user_position = $monthly_values ? $monthly_values->find({ entity_id => $user->id }) : undef; - - return $c->render( json => { - success => Mojo::JSON->true, - today_sum => $today_sum / 100000, - today_count => $today_count, - week_sum => $week_sum / 100000, - week_count => $week_count, - month_sum => $month_sum / 100000, - month_count => $month_count, - user_sum => $user_sum / 100000, - user_count => $user_count, - global_sum => $global_sum / 100000, - global_count => $global_count, - user_position => defined $current_user_position ? $current_user_position->position : 0, - }); + my $c = shift; + + my $user = $c->stash->{api_user}->entity; + + my $today_rs = $user->purchases->today_rs; + my $today_sum = $today_rs->get_column('value')->sum || 0; + my $today_count = $today_rs->count; + + my $week_rs = $user->purchases->week_rs; + my $week_sum = $week_rs->get_column('value')->sum || 0; + my $week_count = $week_rs->count; + + my $month_rs = $user->purchases->month_rs; + my $month_sum = $month_rs->get_column('value')->sum || 0; + my $month_count = $month_rs->count; + + my $user_rs = $user->purchases; + my $user_sum = $user_rs->get_column('value')->sum || 0; + my $user_count = $user_rs->count; + + my $global_rs = $c->schema->resultset('Transaction'); + my $global_sum = $global_rs->get_column('value')->sum || 0; + my $global_count = $global_rs->count; + + my $leaderboard_rs = $c->schema->resultset('Leaderboard'); + my $monthly_board = $leaderboard_rs->get_latest('monthly_total'); + my $monthly_values = $monthly_board->values; + my $current_user_position = + $monthly_values + ? $monthly_values->find( { entity_id => $user->id } ) + : undef; + + return $c->render( + json => { + success => Mojo::JSON->true, + today_sum => $today_sum / 100000, + today_count => $today_count, + week_sum => $week_sum / 100000, + week_count => $week_count, + month_sum => $month_sum / 100000, + month_count => $month_count, + user_sum => $user_sum / 100000, + user_count => $user_count, + global_sum => $global_sum / 100000, + global_count => $global_count, + user_position => defined $current_user_position + ? $current_user_position->position + : 0, + } + ); } sub post_customer { - my $c = shift; - - my $entity = $c->stash->{api_user}->entity; - - my $purchase_rs = $entity->purchases; - - my $duration_weeks = DateTime::Duration->new( weeks => 7 ); - my $end = DateTime->today; - my $start_weeks = $end->clone->subtract_duration( $duration_weeks ); - - my $dtf = $c->schema->storage->datetime_parser; - my $driver = $c->schema->storage->dbh->{Driver}->{Name}; - my $week_transaction_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( - { - purchase_time => { - -between => [ - $dtf->format_datetime($start_weeks), - $dtf->format_datetime($end), - ], - }, - buyer_id => $entity->id, - }, - { - columns => [ + my $c = shift; + + my $entity = $c->stash->{api_user}->entity; + + my $purchase_rs = $entity->purchases; + + my $duration_weeks = DateTime::Duration->new( weeks => 7 ); + my $end = DateTime->today; + my $start_weeks = $end->clone->subtract_duration($duration_weeks); + + my $dtf = $c->schema->storage->datetime_parser; + my $driver = $c->schema->storage->dbh->{Driver}->{Name}; + my $week_transaction_rs = + $c->schema->resultset( 'ViewQuantisedTransaction' . $driver )->search( + { + purchase_time => { + -between => [ + $dtf->format_datetime($start_weeks), + $dtf->format_datetime($end), + ], + }, + buyer_id => $entity->id, + }, { - quantised => 'quantised_weeks', - count => \"COUNT(*)", + columns => [ + { + quantised => 'quantised_weeks', + count => \"COUNT(*)", + } + ], + group_by => 'quantised_weeks', + order_by => { '-asc' => 'quantised_weeks' }, } - ], - group_by => 'quantised_weeks', - order_by => { '-asc' => 'quantised_weeks' }, + ); + + my @all_weeks = $week_transaction_rs->all; + 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 ); + my $count = $week_transaction_rs->count; + + my $weeks = { + first => $first, + second => $second, + max => $max, + sum => $sum, + count => $count, + }; + + my $data = + { cat_total => {}, categories => {}, essentials => {}, cat_list => {} }; + + my $category_list = $c->schema->resultset('Category')->as_hash; + + my $category_purchase_rs = $purchase_rs->search( + {}, + { + join => 'category', + columns => { + category_id => "category.category_id", + value => { sum => 'value' }, + }, + group_by => "category.category_id", + } + ); + + my %cat_total_list; + + for ( $category_purchase_rs->all ) { + my $category = $_->get_column('category_id') || 0; + my $value = ( $_->get_column('value') || 0 ) / 100000; + + $cat_total_list{ $category_list->{$category} } += $value; } - ); - - my @all_weeks = $week_transaction_rs->all; - 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 ); - my $count = $week_transaction_rs->count; - - my $weeks = { - first => $first, - second => $second, - max => $max, - sum => $sum, - count => $count, - }; - - my $data = { cat_total => {}, categories => {}, essentials => {}, cat_list => {} }; - - my $category_list = $c->schema->resultset('Category')->as_hash; - - my $category_purchase_rs = $purchase_rs->search({}, - { - join => 'category', - columns => { - category_id => "category.category_id", - value => { sum => 'value' }, - }, - group_by => "category.category_id", - } - ); - - my %cat_total_list; - - for ( $category_purchase_rs->all ) { - my $category = $_->get_column('category_id') || 0; - my $value = ($_->get_column('value') || 0) / 100000; - - $cat_total_list{$category_list->{$category}} += $value; - } - - my @cat_lists = map { { category => $_, value => $cat_total_list{$_}, - icon => $c->schema->resultset('Category')->as_hash_name_icon->{$_} || 'question'} } sort keys %cat_total_list; - $data->{cat_list} = [ sort { $b->{value} <=> $a->{value} } @cat_lists ]; - - 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 => [ + + my @cat_lists = map { { - quantised => 'quantised_weeks', - value => { sum => 'value' }, - category_id => 'category_id', - essential => 'essential', + category => $_, + value => $cat_total_list{$_}, + icon => $c->schema->resultset('Category')->as_hash_name_icon->{$_} + || 'question' + } + } sort keys %cat_total_list; + $data->{cat_list} = [ sort { $b->{value} <=> $a->{value} } @cat_lists ]; + + 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, }, - ], - group_by => [ qw/ category_id quantised_weeks essential / ], + { + columns => [ + { + quantised => 'quantised_weeks', + value => { sum => 'value' }, + category_id => 'category_id', + essential => 'essential', + }, + ], + group_by => [qw/ category_id quantised_weeks essential /], + } + ); + + 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 $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, - }); + + 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, + } + ); } sub post_organisation { - my $c = shift; - - my $entity = $c->stash->{api_user}->entity; - - my $purchase_rs = $entity->purchases; - - my $duration_weeks = DateTime::Duration->new( weeks => 7 ); - my $end = DateTime->today; - my $start_weeks = $end->clone->subtract_duration( $duration_weeks ); - - my $dtf = $c->schema->storage->datetime_parser; - my $driver = $c->schema->storage->dbh->{Driver}->{Name}; - my $week_transaction_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( - { - purchase_time => { - -between => [ - $dtf->format_datetime($start_weeks), - $dtf->format_datetime($end), - ], - }, - buyer_id => $entity->id, - }, - { - columns => [ + my $c = shift; + + my $entity = $c->stash->{api_user}->entity; + + my $purchase_rs = $entity->purchases; + + my $duration_weeks = DateTime::Duration->new( weeks => 7 ); + my $end = DateTime->today; + my $start_weeks = $end->clone->subtract_duration($duration_weeks); + + my $dtf = $c->schema->storage->datetime_parser; + my $driver = $c->schema->storage->dbh->{Driver}->{Name}; + my $week_transaction_rs = + $c->schema->resultset( 'ViewQuantisedTransaction' . $driver )->search( + { + purchase_time => { + -between => [ + $dtf->format_datetime($start_weeks), + $dtf->format_datetime($end), + ], + }, + buyer_id => $entity->id, + }, { - quantised => 'quantised_weeks', - count => \"COUNT(*)", + columns => [ + { + quantised => 'quantised_weeks', + count => \"COUNT(*)", + } + ], + group_by => 'quantised_weeks', + order_by => { '-asc' => 'quantised_weeks' }, } - ], - group_by => 'quantised_weeks', - order_by => { '-asc' => 'quantised_weeks' }, + ); + + my @all_weeks = $week_transaction_rs->all; + 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 ); + my $count = $week_transaction_rs->count; + + my $weeks = { + first => $first, + second => $second, + max => $max, + sum => $sum, + count => $count, + }; + + my $data = { + cat_total => {}, + categories => {}, + essentials => {}, + cat_list => {}, + sector_monthly => {} + }; + + my $category_list = $c->schema->resultset('Category')->as_hash; + + my $category_purchase_rs = $purchase_rs->search( + {}, + { + join => 'category', + columns => { + category_id => "category.category_id", + value => { sum => 'value' }, + }, + group_by => "category.category_id", + } + ); + + my %cat_total_list; + + for ( $category_purchase_rs->all ) { + my $category = $_->get_column('category_id') || 0; + my $value = ( $_->get_column('value') || 0 ) / 100000; + + $cat_total_list{ $category_list->{$category} } += $value; } - ); - - my @all_weeks = $week_transaction_rs->all; - 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 ); - my $count = $week_transaction_rs->count; - - my $weeks = { - first => $first, - second => $second, - max => $max, - sum => $sum, - count => $count, - }; - - my $data = { - cat_total => {}, - categories => {}, - essentials => {}, - cat_list => {}, - sector_monthly => {} - }; - - my $category_list = $c->schema->resultset('Category')->as_hash; - - my $category_purchase_rs = $purchase_rs->search({}, - { - join => 'category', - columns => { - category_id => "category.category_id", - value => { sum => 'value' }, - }, - group_by => "category.category_id", - } - ); - - my %cat_total_list; - - for ( $category_purchase_rs->all ) { - my $category = $_->get_column('category_id') || 0; - my $value = ($_->get_column('value') || 0) / 100000; - - $cat_total_list{$category_list->{$category}} += $value; - } - - my @cat_lists = map { { category => $_, value => $cat_total_list{$_}, - icon => $c->schema->resultset('Category')->as_hash_name_icon->{$_} || 'question'} } sort keys %cat_total_list; - $data->{cat_list} = [ sort { $b->{value} <=> $a->{value} } @cat_lists ]; - - 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 => [ + + my @cat_lists = map { { - quantised => 'quantised_weeks', - value => { sum => 'value' }, - category_id => 'category_id', - essential => 'essential', + category => $_, + value => $cat_total_list{$_}, + icon => $c->schema->resultset('Category')->as_hash_name_icon->{$_} + || 'question' + } + } sort keys %cat_total_list; + $data->{cat_list} = [ sort { $b->{value} <=> $a->{value} } @cat_lists ]; + + 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, }, - ], - group_by => [ qw/ category_id quantised_weeks essential / ], + { + columns => [ + { + quantised => 'quantised_weeks', + value => { sum => 'value' }, + category_id => 'category_id', + essential => 'essential', + }, + ], + group_by => [qw/ category_id quantised_weeks essential /], + } + ); + + 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 ]; } - ); - - 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 ]; - } - - # my $start_year_monthly = DateTime->now->truncate( to => 'year' ); - # my $current_year_monthly = DateTime->now->add( months => 1, end_of_month => 'limit' ); - # my $monthly_sector_transactions_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( - # { - # purchase_time => { - # -between => [ - # $dtf->format_datetime($start_year_monthly), - # $dtf->format_datetime($current_year_monthly), - # ], - # }, - # buyer_id => $entity->id, - # }, - # { - # columns => [ - # { - # quantised => 'quantised_months', - # value => { sum => 'value' }, - # }, - # ], - # group_by => [ qw/ quantised_months / ], - # } - # ); - # - # for my $sector_transaction ( $monthly_sector_transactions_rs->all ) { - # my $quantised = $c->db_datetime_parser->parse_datetime($cat_trans->get_column('quantised')); - # my $months = $c->format_iso_date( $quantised ) || 0; - # my $category = $cat_trans->get_column('category_id') || 0; - # my $value = ($cat_trans->get_column('value') || 0) / 100000; - # } - - return $c->render( json => { - success => Mojo::JSON->true, - data => $data, - weeks => $weeks, - }); + +# my $start_year_monthly = DateTime->now->truncate( to => 'year' ); +# my $current_year_monthly = DateTime->now->add( months => 1, end_of_month => 'limit' ); +# my $monthly_sector_transactions_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( +# { +# purchase_time => { +# -between => [ +# $dtf->format_datetime($start_year_monthly), +# $dtf->format_datetime($current_year_monthly), +# ], +# }, +# buyer_id => $entity->id, +# }, +# { +# columns => [ +# { +# quantised => 'quantised_months', +# value => { sum => 'value' }, +# }, +# ], +# group_by => [ qw/ quantised_months / ], +# } +# ); +# +# for my $sector_transaction ( $monthly_sector_transactions_rs->all ) { +# my $quantised = $c->db_datetime_parser->parse_datetime($cat_trans->get_column('quantised')); +# my $months = $c->format_iso_date( $quantised ) || 0; +# my $category = $cat_trans->get_column('category_id') || 0; +# my $value = ($cat_trans->get_column('value') || 0) / 100000; +# } + + return $c->render( + json => { + success => Mojo::JSON->true, + data => $data, + weeks => $weeks, + } + ); } sub post_leaderboards { - my $c = shift; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - - my $leaderboard_rs = $c->schema->resultset('Leaderboard'); - - $validation->required('type')->in_resultset( 'type', $leaderboard_rs ); - - return $c->api_validation_error if $validation->has_error; - - my $today_board = $leaderboard_rs->get_latest( $validation->param('type') ); - - my $today_values = $today_board->values->search( - {}, - { - order_by => { -asc => 'me.position' }, - columns => [ - qw/ - me.value - me.trend - me.position - /, - { display_name => 'customer.display_name' }, - ], - join => { entity => 'customer' }, - }, - ); - $today_values->result_class( 'DBIx::Class::ResultClass::HashRefInflator' ); - - my @leaderboard_array = $today_values->all; - - if ( $validation->param('type') =~ /total$/ ) { - @leaderboard_array = (map { - { - %$_, - value => $_->{value} / 100000, - } - } @leaderboard_array); - } - - my $current_user_position = $today_values->find({ entity_id => $c->stash->{api_user}->entity->id }); - - return $c->render( json => { - success => Mojo::JSON->true, - leaderboard => [ @leaderboard_array ], - user_position => defined $current_user_position ? $current_user_position->{position} : 0, - }); -} + my $c = shift; -sub post_leaderboards_paged { - my $c = shift; + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); + my $leaderboard_rs = $c->schema->resultset('Leaderboard'); - my $leaderboard_rs = $c->schema->resultset('Leaderboard'); + $validation->required('type')->in_resultset( 'type', $leaderboard_rs ); - $validation->required('type')->in_resultset( 'type', $leaderboard_rs ); - $validation->optional('page')->number; + return $c->api_validation_error if $validation->has_error; - return $c->api_validation_error if $validation->has_error; + my $today_board = $leaderboard_rs->get_latest( $validation->param('type') ); - my $page = 1; + my $today_values = $today_board->values->search( + {}, + { + order_by => { -asc => 'me.position' }, + columns => [ + qw/ + me.value + me.trend + me.position + /, + { display_name => 'customer.display_name' }, + ], + join => { entity => 'customer' }, + }, + ); + $today_values->result_class('DBIx::Class::ResultClass::HashRefInflator'); - my $today_board = $leaderboard_rs->get_latest( $validation->param('type') ); - my @leaderboard_array; - my $current_user_position; - my $values_count = 0; - if ( defined $today_board ) { + my @leaderboard_array = $today_values->all; - if ( !defined $validation->param('page') || $validation->param('page') < 1 ) { - my $user_position = $today_board->values->find({ entity_id => $c->stash->{api_user}->entity->id }); - $page = int(defined $user_position ? $user_position->{position} : 0 / 10) + 1; - } else { - $page = $validation->param('page'); + if ( $validation->param('type') =~ /total$/ ) { + @leaderboard_array = ( + map { + { + %$_, + value => $_->{value} / 100000, + } + } @leaderboard_array + ); } - my $today_values = $today_board->values->search( - {}, - { - page => $page, - rows => 10, - order_by => { -asc => 'me.position' }, - columns => [ - qw/ - me.value - me.trend - me.position - /, - { display_name => 'customer.display_name' }, - ], - join => { entity => 'customer' }, - }, + my $current_user_position = + $today_values->find( { entity_id => $c->stash->{api_user}->entity->id } ); + + return $c->render( + json => { + success => Mojo::JSON->true, + leaderboard => [@leaderboard_array], + user_position => defined $current_user_position + ? $current_user_position->{position} + : 0, + } ); - $today_values->result_class( 'DBIx::Class::ResultClass::HashRefInflator' ); +} - @leaderboard_array = $today_values->all; +sub post_leaderboards_paged { + my $c = shift; - $values_count = $today_values->pager->total_entries; + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); - if ( $validation->param('type') =~ /total$/ ) { - @leaderboard_array = (map { + my $leaderboard_rs = $c->schema->resultset('Leaderboard'); + + $validation->required('type')->in_resultset( 'type', $leaderboard_rs ); + $validation->optional('page')->number; + + return $c->api_validation_error if $validation->has_error; + + my $page = 1; + + my $today_board = $leaderboard_rs->get_latest( $validation->param('type') ); + my @leaderboard_array; + my $current_user_position; + my $values_count = 0; + if ( defined $today_board ) { + + if ( !defined $validation->param('page') + || $validation->param('page') < 1 ) { - %$_, - value => $_->{value} / 100000, + my $user_position = $today_board->values->find( + { entity_id => $c->stash->{api_user}->entity->id } ); + $page = int( + defined $user_position ? $user_position->{position} : 0 / 10 ) + + 1; + } + else { + $page = $validation->param('page'); + } + + my $today_values = $today_board->values->search( + {}, + { + page => $page, + rows => 10, + order_by => { -asc => 'me.position' }, + columns => [ + qw/ + me.value + me.trend + me.position + /, + { display_name => 'customer.display_name' }, + ], + join => { entity => 'customer' }, + }, + ); + $today_values->result_class( + 'DBIx::Class::ResultClass::HashRefInflator'); + + @leaderboard_array = $today_values->all; + + $values_count = $today_values->pager->total_entries; + + if ( $validation->param('type') =~ /total$/ ) { + @leaderboard_array = ( + map { + { + %$_, + value => $_->{value} / 100000, + } + } @leaderboard_array + ); } - } @leaderboard_array); - } - $current_user_position = $today_values->find({ entity_id => $c->stash->{api_user}->entity->id }); - } - return $c->render( json => { - success => Mojo::JSON->true, - leaderboard => [ @leaderboard_array ], - user_position => defined $current_user_position ? $current_user_position->{position} : 0, - page => $page, - count => $values_count, - }); + $current_user_position = $today_values->find( + { entity_id => $c->stash->{api_user}->entity->id } ); + } + return $c->render( + json => { + success => Mojo::JSON->true, + leaderboard => [@leaderboard_array], + user_position => defined $current_user_position + ? $current_user_position->{position} + : 0, + page => $page, + count => $values_count, + } + ); } 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; - } + 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; + } } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm index 221eaf6..7d5804e 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm @@ -3,176 +3,213 @@ use Mojo::Base 'Mojolicious::Controller'; use Mojo::JSON; has error_messages => sub { - return { - email => { - 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 }, - }, - }; + return { + email => { + 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 }, + }, + }; }; sub post_transaction_list_purchases { - my $c = shift; - - my $user = $c->stash->{api_user}; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - $validation->optional('page')->number; - - return $c->api_validation_error if $validation->has_error; - - my $transactions = $user->entity->purchases->search( - undef, { - page => $validation->param('page') || 1, - rows => 10, - order_by => { -desc => 'purchase_time' }, - }, - ); - - 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, - value => $_->value / 100000, - purchase_time => $c->format_iso_datetime($_->purchase_time), - ( $_->meta ? ( - net_value => $_->meta->net_value / 100000, - sales_tax_value => $_->meta->sales_tax_value / 100000, - gross_value => $_->meta->gross_value / 100000, - ) : ( - net_value => undef, - sales_tax_value => undef, - gross_value => undef, - )), - - }} $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) || undef, - essential => $_->essential, - category => $_->category_id || 0, - 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, - }); -} + my $c = shift; -sub update_recurring { - my $c = shift; + my $user = $c->stash->{api_user}; - my $user = $c->stash->{api_user}; + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->optional('page')->number; - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - $validation->required('id'); + return $c->api_validation_error if $validation->has_error; - return $c->api_validation_error if $validation->has_error; + my $transactions = $user->entity->purchases->search( + undef, + { + page => $validation->param('page') || 1, + rows => 10, + order_by => { -desc => 'purchase_time' }, + }, + ); - my $id = $validation->param('id'); + 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, + value => $_->value / 100000, + purchase_time => $c->format_iso_datetime( $_->purchase_time ), + ( + $_->meta + ? ( + net_value => $_->meta->net_value / 100000, + sales_tax_value => $_->meta->sales_tax_value / 100000, + gross_value => $_->meta->gross_value / 100000, + ) + : ( + net_value => undef, + sales_tax_value => undef, + gross_value => undef, + ) + ), + + } + } $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 ) + || undef, + essential => $_->essential, + category => $_->category_id || 0, + recurring_period => $_->recurring_period, + } + } $recurring_transactions->all + ); - 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, + json => { + success => Mojo::JSON->true, + transactions => \@transaction_list, + recurring_transactions => \@recurring_transaction_list, + page_no => $transactions->pager->total_entries, + } + ); +} + +sub update_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, + ); + } + + $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', + } ); - } - - $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 $c = shift; - my $user = $c->stash->{api_user}; + my $user = $c->stash->{api_user}; - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - $validation->required('id'); + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->required('id'); - return $c->api_validation_error if $validation->has_error; + return $c->api_validation_error if $validation->has_error; - my $id = $validation->param('id'); + 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, - ); - } + 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; + $recur_transaction->delete; - return $c->render( json => { - success => Mojo::JSON->true, - message => 'Recurring Transaction Deleted Successfully', - }); + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Recurring Transaction Deleted Successfully', + } + ); } diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index 2bcd161..443845c 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -48,277 +48,338 @@ The postcode of an organisation, optional key. Used when transaction_Type is 3. =cut has error_messages => sub { - return { - transaction_type => { - required => { message => 'transaction type is missing.', status => 400 }, - in => { message => 'transaction type is not a valid value.', status => 400 }, - }, - transaction_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 }, - }, - purchase_time => { - required => { message => 'purchase time is missing', status => 400 }, - is_full_iso_datetime => { message => 'purchase time is in incorrect format', status => 400 }, - }, - file => { - required => { message => 'No file uploaded', status => 400 }, - upload => { message => 'file key does not contain a file', status => 400 }, - filetype => { message => 'File must be of type image/jpeg', status => 400 }, - }, - organisation_id => { - required => { message => 'existing organisation ID is missing', status => 400 }, - number => { message => 'organisation ID is not a number', status => 400 }, - in_resultset => { message => 'organisation ID does not exist in the database', status => 400 }, - }, - organisation_name => { - required => { message => 'organisation name is missing', status => 400 }, - }, - category => { - in_resultset => { message => 'Category is invalid', status => 400 }, - }, - town => { - required => { message => 'town/city is missing', status => 400 }, - }, - search_name => { - required => { message => 'search name is missing', status => 400 }, - }, - postcode => { - postcode => { message => 'postcode must be valid', status => 400 }, - }, - }; + return { + transaction_type => { + required => + { message => 'transaction type is missing.', status => 400 }, + in => { + message => 'transaction type is not a valid value.', + status => 400 + }, + }, + transaction_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 + }, + }, + purchase_time => { + required => + { message => 'purchase time is missing', status => 400 }, + is_full_iso_datetime => { + message => 'purchase time is in incorrect format', + status => 400 + }, + }, + file => { + required => { message => 'No file uploaded', status => 400 }, + upload => + { message => 'file key does not contain a file', status => 400 }, + filetype => + { message => 'File must be of type image/jpeg', status => 400 }, + }, + organisation_id => { + required => { + message => 'existing organisation ID is missing', + status => 400 + }, + number => + { message => 'organisation ID is not a number', status => 400 }, + in_resultset => { + message => 'organisation ID does not exist in the database', + status => 400 + }, + }, + organisation_name => { + required => + { message => 'organisation name is missing', status => 400 }, + }, + category => { + in_resultset => { message => 'Category is invalid', status => 400 }, + }, + town => { + required => { message => 'town/city is missing', status => 400 }, + }, + search_name => { + required => { message => 'search name is missing', status => 400 }, + }, + postcode => { + postcode => { message => 'postcode must be valid', status => 400 }, + }, + }; }; sub post_upload { - my $c = shift; + my $c = shift; - my $user = $c->stash->{api_user}; + my $user = $c->stash->{api_user}; - my $validation = $c->validation; + my $validation = $c->validation; - # Test for file before loading the JSON in to the validator - $validation->optional('file')->upload->filetype('image/jpeg'); + # Test for file before loading the JSON in to the validator + $validation->optional('file')->upload->filetype('image/jpeg'); - $validation->input( $c->stash->{api_json} ); + $validation->input( $c->stash->{api_json} ); - $validation->required('transaction_value')->number->gt_num(0); - $validation->required('transaction_type')->in( 1, 2, 3 ); + $validation->required('transaction_value')->number->gt_num(0); + $validation->required('transaction_type')->in( 1, 2, 3 ); - #Check a proper purchase time was submitted - $validation->optional('purchase_time')->is_full_iso_datetime; - $validation->optional('category')->in_resultset( 'id', $c->schema->resultset('Category')); - $validation->optional('essential'); - $validation->optional('recurring'); + #Check a proper purchase time was submitted + $validation->optional('purchase_time')->is_full_iso_datetime; + $validation->optional('category') + ->in_resultset( 'id', $c->schema->resultset('Category') ); + $validation->optional('essential'); + $validation->optional('recurring'); - # First pass of required items - return $c->api_validation_error if $validation->has_error; + # First pass of required items + return $c->api_validation_error if $validation->has_error; - my $type = $validation->param('transaction_type'); + my $type = $validation->param('transaction_type'); - my $organisation; + my $organisation; - if ( $type == 1 ) { - # Validated Organisation - my $valid_org_rs = $c->schema->resultset('Organisation')->search({ - pending => 0, - entity_id => { "!=" => $user->entity_id }, - }); - $validation->required('organisation_id')->number->in_resultset( 'id', $valid_org_rs ); + if ( $type == 1 ) { - return $c->api_validation_error if $validation->has_error; + # Validated Organisation + my $valid_org_rs = $c->schema->resultset('Organisation')->search( + { + pending => 0, + entity_id => { "!=" => $user->entity_id }, + } + ); + $validation->required('organisation_id') + ->number->in_resultset( 'id', $valid_org_rs ); - $organisation = $valid_org_rs->find( $validation->param('organisation_id') ); + return $c->api_validation_error if $validation->has_error; - } elsif ( $type == 2 ) { - # Unvalidated Organisation - my $valid_org_rs = $c->schema->resultset('Organisation')->search({ - submitted_by_id => $user->id, - pending => 1, - entity_id => { "!=" => $user->entity_id }, - }); - $validation->required('organisation_id')->number->in_resultset( 'id', $valid_org_rs ); + $organisation = + $valid_org_rs->find( $validation->param('organisation_id') ); - return $c->api_validation_error if $validation->has_error; + } + elsif ( $type == 2 ) { - $organisation = $valid_org_rs->find( $validation->param('organisation_id') ); + # Unvalidated Organisation + my $valid_org_rs = $c->schema->resultset('Organisation')->search( + { + submitted_by_id => $user->id, + pending => 1, + entity_id => { "!=" => $user->entity_id }, + } + ); + $validation->required('organisation_id') + ->number->in_resultset( 'id', $valid_org_rs ); - } elsif ( $type == 3 ) { - # Unknown Organisation - $validation->required('organisation_name'); - $validation->optional('street_name'); - $validation->optional('town'); - $validation->optional('postcode')->postcode; + return $c->api_validation_error if $validation->has_error; - return $c->api_validation_error if $validation->has_error; + $organisation = + $valid_org_rs->find( $validation->param('organisation_id') ); - my $location = $c->get_location_from_postcode( - $validation->param('postcode'), - 'organisation', - ); + } + elsif ( $type == 3 ) { + + # Unknown Organisation + $validation->required('organisation_name'); + $validation->optional('street_name'); + $validation->optional('town'); + $validation->optional('postcode')->postcode; + + return $c->api_validation_error if $validation->has_error; + + my $location = + $c->get_location_from_postcode( $validation->param('postcode'), + 'organisation', ); + + my $entity = $c->schema->resultset('Entity')->create_org( + { + submitted_by_id => $user->id, + name => $validation->param('organisation_name'), + street_name => $validation->param('street_name'), + town => $validation->param('town'), + postcode => $validation->param('postcode'), + ( + defined $location + ? (%$location) + : ( latitude => undef, longitude => undef ) + ), + pending => 1, + } + ); + $organisation = $entity->organisation; + } - my $entity = $c->schema->resultset('Entity')->create_org({ - submitted_by_id => $user->id, - name => $validation->param('organisation_name'), - street_name => $validation->param('street_name'), - town => $validation->param('town'), - postcode => $validation->param('postcode'), - ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), - pending => 1, - }); - $organisation = $entity->organisation; - } - - unless ( defined $organisation ) { - return $c->render( - json => { - success => Mojo::JSON->false, - message => 'Error Finding Organisation', - error => 'organisation_error', - }, - status => 400, + unless ( defined $organisation ) { + return $c->render( + json => { + success => Mojo::JSON->false, + message => 'Error Finding Organisation', + error => 'organisation_error', + }, + status => 400, + ); + } + + my $transaction_value = $validation->param('transaction_value'); + my $upload = $validation->param('file'); + my $purchase_time = + $c->parse_iso_datetime( $validation->param('purchase_time') || '' ); + $purchase_time ||= DateTime->now(); + my $file = defined $upload ? $c->store_file_from_upload($upload) : undef; + my $category = $validation->param('category'); + my $essential = $validation->param('essential'); + my $recurring_period = $validation->param('recurring'); + my $distance = + $c->get_distance_from_coords( $user->entity->type_object, $organisation ); + + my $new_transaction = $organisation->entity->create_related( + 'sales', + { + buyer => $user->entity, + value => $transaction_value * 100000, + ( defined $file ? ( proof_image => $file ) : () ), + purchase_time => $c->format_db_datetime($purchase_time), + essential => ( defined $essential ? $essential : 0 ), + distance => $distance, + } ); - } - - my $transaction_value = $validation->param('transaction_value'); - my $upload = $validation->param('file'); - my $purchase_time = $c->parse_iso_datetime($validation->param('purchase_time') || ''); - $purchase_time ||= DateTime->now(); - my $file = defined $upload ? $c->store_file_from_upload( $upload ) : undef; - my $category = $validation->param('category'); - my $essential = $validation->param('essential'); - my $recurring_period = $validation->param('recurring'); - my $distance = $c->get_distance_from_coords( $user->entity->type_object, $organisation ); - - my $new_transaction = $organisation->entity->create_related( - 'sales', - { - buyer => $user->entity, - value => $transaction_value * 100000, - ( defined $file ? ( proof_image => $file ) : () ), - purchase_time => $c->format_db_datetime($purchase_time), - essential => ( defined $essential ? $essential : 0 ), - distance => $distance, + + unless ( defined $new_transaction ) { + return $c->render( + json => { + success => Mojo::JSON->false, + message => 'Error Adding Transaction', + error => 'transaction_error', + }, + status => 400, + ); + } + + if ( defined $category ) { + $c->schema->resultset('TransactionCategory')->create( + { + category_id => $category, + transaction_id => $new_transaction->id, + } + ); + } + + if ( defined $recurring_period ) { + $c->schema->resultset('TransactionRecurring')->create( + { + buyer => $user->entity, + seller => $organisation->entity, + value => $transaction_value * 100000, + start_time => $c->format_db_datetime($purchase_time), + essential => ( defined $essential ? $essential : 0 ), + distance => $distance, + category_id => ( defined $category ? $category : undef ), + recurring_period => $recurring_period, + } + ); } - ); - unless ( defined $new_transaction ) { return $c->render( - json => { - success => Mojo::JSON->false, - message => 'Error Adding Transaction', - error => 'transaction_error', - }, - status => 400, + json => { + success => Mojo::JSON->true, + message => 'Upload Successful', + } ); - } - - if ( defined $category ) { - $c->schema->resultset('TransactionCategory')->create({ - category_id => $category, - transaction_id => $new_transaction->id, - }); - } - - if ( defined $recurring_period ) { - $c->schema->resultset('TransactionRecurring')->create({ - buyer => $user->entity, - seller => $organisation->entity, - value => $transaction_value * 100000, - start_time => $c->format_db_datetime($purchase_time), - essential => ( defined $essential ? $essential : 0 ), - distance => $distance, - category_id => ( defined $category ? $category : undef ), - recurring_period => $recurring_period, - }); - } - - return $c->render( json => { - success => Mojo::JSON->true, - message => 'Upload Successful', - }); } sub post_category { - my $c = shift; - my $self = $c; + my $c = shift; + my $self = $c; - my $category_list = $c->schema->resultset('Category')->as_hash; - delete $category_list->{0}; + my $category_list = $c->schema->resultset('Category')->as_hash; + delete $category_list->{0}; - return $self->render( json => { - success => Mojo::JSON->true, - categories => $category_list, - }); + return $self->render( + json => { + success => Mojo::JSON->true, + categories => $category_list, + } + ); } # TODO Limit search results, possibly paginate them? # TODO Search by location as well sub post_search { - my $c = shift; - my $self = $c; - - my $user = $c->stash->{api_user}; - - my $validation = $c->validation; - - $validation->input( $c->stash->{api_json} ); - - $validation->required('search_name'); - $validation->optional('page')->number; - - return $c->api_validation_error if $validation->has_error; - - my $search_name = $validation->param('search_name'); - - my $search_stmt = [ 'LOWER("name") LIKE ?', '%' . lc $search_name . '%' ]; - - my $org_rs = $c->schema->resultset('Organisation'); - my $valid_orgs_rs = $org_rs->search({ - pending => 0, - entity_id => { "!=" => $user->entity_id }, - }, - { - page => $validation->param('page') || 1, - rows => 10, - order_by => { -desc => 'name' }, - })->search( - \$search_stmt, - ); - - my $pending_orgs_rs = $org_rs->search({ - pending => 1, - submitted_by_id => $c->stash->{api_user}->id, - entity_id => { "!=" => $user->entity_id }, - })->search( - \$search_stmt, - ); - - my @valid_orgs = ( - map {{ - id => $_->id, - name => $_->name, - street_name => $_->street_name, - town => $_->town, - postcode => $_->postcode, - }} $valid_orgs_rs->all - ); - - my @pending_orgs = ( - map {{ - id => $_->id, - name => $_->name, - street_name => $_->street_name, - town => $_->town, - postcode => $_->postcode, - }} $pending_orgs_rs->all - ); - - return $self->render( json => { - success => Mojo::JSON->true, - validated => \@valid_orgs, - unvalidated => \@pending_orgs, - }); + my $c = shift; + my $self = $c; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + + $validation->input( $c->stash->{api_json} ); + + $validation->required('search_name'); + $validation->optional('page')->number; + + return $c->api_validation_error if $validation->has_error; + + my $search_name = $validation->param('search_name'); + + my $search_stmt = [ 'LOWER("name") LIKE ?', '%' . lc $search_name . '%' ]; + + my $org_rs = $c->schema->resultset('Organisation'); + my $valid_orgs_rs = $org_rs->search( + { + pending => 0, + entity_id => { "!=" => $user->entity_id }, + }, + { + page => $validation->param('page') || 1, + rows => 10, + order_by => { -desc => 'name' }, + } + )->search( \$search_stmt, ); + + my $pending_orgs_rs = $org_rs->search( + { + pending => 1, + submitted_by_id => $c->stash->{api_user}->id, + entity_id => { "!=" => $user->entity_id }, + } + )->search( \$search_stmt, ); + + my @valid_orgs = ( + map { + { + id => $_->id, + name => $_->name, + street_name => $_->street_name, + town => $_->town, + postcode => $_->postcode, + } + } $valid_orgs_rs->all + ); + + my @pending_orgs = ( + map { + { + id => $_->id, + name => $_->name, + street_name => $_->street_name, + town => $_->town, + postcode => $_->postcode, + } + } $pending_orgs_rs->all + ); + + return $self->render( + json => { + success => Mojo::JSON->true, + validated => \@valid_orgs, + unvalidated => \@pending_orgs, + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/User.pm b/lib/Pear/LocalLoop/Controller/Api/User.pm index c500164..9e38af6 100644 --- a/lib/Pear/LocalLoop/Controller/Api/User.pm +++ b/lib/Pear/LocalLoop/Controller/Api/User.pm @@ -3,191 +3,252 @@ use Mojo::Base 'Mojolicious::Controller'; use Mojo::JSON; has error_messages => sub { - return { - day => { - is_iso_datetime => { message => 'Invalid ISO8601 Datetime', status => 400 }, - }, - name => { - required => { message => 'No name sent or was blank.', status => 400 }, - }, - display_name => { - required => { message => 'No display name sent or was blank.', status => 400 }, - }, - full_name => { - required => { message => 'No full name sent or was blank.', status => 400 }, - }, - email => { - required => { message => 'No email sent.', status => 400 }, - email => { message => 'Email is invalid.', status => 400 }, - }, - postcode => { - required => { message => 'No postcode sent.', status => 400 }, - postcode => { message => 'Postcode is invalid', status => 400 }, - }, - password => { - required => { message => 'No password sent.', status => 400 }, - }, - street_name => { - required => { message => 'No street name sent.', status => 400 }, - }, - town => { - required => { message => 'No town/city sent.', status => 400 }, - }, - sector => { - required => { message => 'No sector sent.', status => 400 }, - }, - }; + return { + day => { + is_iso_datetime => + { message => 'Invalid ISO8601 Datetime', status => 400 }, + }, + name => { + required => + { message => 'No name sent or was blank.', status => 400 }, + }, + display_name => { + required => { + message => 'No display name sent or was blank.', + status => 400 + }, + }, + full_name => { + required => + { message => 'No full name sent or was blank.', status => 400 }, + }, + email => { + required => { message => 'No email sent.', status => 400 }, + email => { message => 'Email is invalid.', status => 400 }, + }, + postcode => { + required => { message => 'No postcode sent.', status => 400 }, + postcode => { message => 'Postcode is invalid', status => 400 }, + }, + password => { + required => { message => 'No password sent.', status => 400 }, + }, + street_name => { + required => { message => 'No street name sent.', status => 400 }, + }, + town => { + required => { message => 'No town/city sent.', status => 400 }, + }, + sector => { + required => { message => 'No sector sent.', status => 400 }, + }, + }; }; sub post_account { - my $c = shift; - - my $user = $c->stash->{api_user}; - my $user_result = $c->schema->resultset('User')->find({ id => $c->stash->{api_user}->id }); - - if ( defined $user_result ) { - my $email = $user_result->email; - - if ( $user_result->type eq 'customer' ) { - my $customer = $user_result->entity->customer; - my $full_name = $customer->full_name; - my $display_name = $customer->display_name; - my $postcode = $customer->postcode; - return $c->render( json => { - success => Mojo::JSON->true, - full_name => $full_name, - display_name => $display_name, - email => $email, - postcode => $postcode, - location => { - latitude => (defined $customer->latitude ? $customer->latitude * 1 : undef), - longitude => (defined $customer->longitude ? $customer->longitude * 1 : undef), - }, - }); - } elsif ( $user_result->type eq 'organisation' ) { - my $organisation = $user_result->entity->organisation; - my $name = $organisation->name; - my $postcode = $organisation->postcode; - my $street_name = $organisation->street_name; - my $town = $organisation->town; - my $sector = $organisation->sector; - return $c->render( json => { - success => Mojo::JSON->true, - town => $town, - name => $name, - sector => $sector, - street_name => $street_name, - email => $email, - postcode => $postcode, - location => { - latitude => (defined $organisation->latitude ? $organisation->latitude * 1 : undef), - longitude => (defined $organisation->longitude ? $organisation->longitude * 1 : undef), - }, - }); - } else { - return $c->render( + my $c = shift; + + my $user = $c->stash->{api_user}; + my $user_result = $c->schema->resultset('User') + ->find( { id => $c->stash->{api_user}->id } ); + + if ( defined $user_result ) { + my $email = $user_result->email; + + if ( $user_result->type eq 'customer' ) { + my $customer = $user_result->entity->customer; + my $full_name = $customer->full_name; + my $display_name = $customer->display_name; + my $postcode = $customer->postcode; + return $c->render( + json => { + success => Mojo::JSON->true, + full_name => $full_name, + display_name => $display_name, + email => $email, + postcode => $postcode, + location => { + latitude => ( + defined $customer->latitude + ? $customer->latitude * 1 + : undef + ), + longitude => ( + defined $customer->longitude + ? $customer->longitude * 1 + : undef + ), + }, + } + ); + } + elsif ( $user_result->type eq 'organisation' ) { + my $organisation = $user_result->entity->organisation; + my $name = $organisation->name; + my $postcode = $organisation->postcode; + my $street_name = $organisation->street_name; + my $town = $organisation->town; + my $sector = $organisation->sector; + return $c->render( + json => { + success => Mojo::JSON->true, + town => $town, + name => $name, + sector => $sector, + street_name => $street_name, + email => $email, + postcode => $postcode, + location => { + latitude => ( + defined $organisation->latitude + ? $organisation->latitude * 1 + : undef + ), + longitude => ( + defined $organisation->longitude + ? $organisation->longitude * 1 + : undef + ), + }, + } + ); + } + else { + return $c->render( + json => { + success => Mojo::JSON->false, + message => 'Invalid Server Error.', + }, + status => 500 + ); + } + + } + return $c->render( json => { - success => Mojo::JSON->false, - message => 'Invalid Server Error.', + success => Mojo::JSON->false, + message => 'Email or password is invalid.', }, - status => 500 - ); - } - - } - return $c->render( - json => { - success => Mojo::JSON->false, - message => 'Email or password is invalid.', - }, - status => 401 - ); + status => 401 + ); } sub post_account_update { - my $c = shift; + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->required('password'); - my $user = $c->stash->{api_user}; + return $c->api_validation_error if $validation->has_error; - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - $validation->required('password'); + if ( !$user->check_password( $validation->param('password') ) ) { + return $c->render( + json => { + success => Mojo::JSON->false, + message => 'password is invalid.', + }, + status => 401 + ); + } + + my $user_rs = $c->schema->resultset('User')->search( + { + id => { "!=" => $user->id }, + } + ); - return $c->api_validation_error if $validation->has_error; + $validation->required('email')->not_in_resultset( 'email', $user_rs ); + $validation->required('postcode')->postcode; + $validation->optional('new_password'); + + if ( $user->type eq 'customer' ) { + $validation->required('display_name'); + $validation->required('full_name'); + } + elsif ( $user->type eq 'organisation' ) { + $validation->required('name'); + $validation->required('street_name'); + $validation->required('town'); + $validation->required('sector'); + } + + return $c->api_validation_error if $validation->has_error; + + my $location = + $c->get_location_from_postcode( $validation->param('postcode'), + $user->type, ); + + if ( $user->type eq 'customer' ) { + + $c->schema->txn_do( + sub { + $user->entity->customer->update( + { + full_name => $validation->param('full_name'), + display_name => $validation->param('display_name'), + postcode => $validation->param('postcode'), + ( + defined $location + ? (%$location) + : ( latitude => undef, longitude => undef ) + ), + } + ); + $user->update( + { + email => $validation->param('email'), + ( + defined $validation->param('new_password') + ? ( password => $validation->param('new_password') ) + : () + ), + } + ); + } + ); + + } + elsif ( $user->type eq 'organisation' ) { + + $c->schema->txn_do( + sub { + $user->entity->organisation->update( + { + name => $validation->param('name'), + street_name => $validation->param('street_name'), + town => $validation->param('town'), + sector => $validation->param('sector'), + postcode => $validation->param('postcode'), + ( + defined $location + ? (%$location) + : ( latitude => undef, longitude => undef ) + ), + } + ); + $user->update( + { + email => $validation->param('email'), + ( + defined $validation->param('new_password') + ? ( password => $validation->param('new_password') ) + : () + ), + } + ); + } + ); + } - if ( ! $user->check_password($validation->param('password')) ) { return $c->render( - json => { - success => Mojo::JSON->false, - message => 'password is invalid.', - }, - status => 401 + json => { + success => Mojo::JSON->true, + message => 'Edited Account Successfully', + } ); - } - - my $user_rs = $c->schema->resultset('User')->search({ - id => { "!=" => $user->id }, - }); - - $validation->required('email')->not_in_resultset( 'email', $user_rs ); - $validation->required('postcode')->postcode; - $validation->optional('new_password'); - - if ( $user->type eq 'customer' ) { - $validation->required('display_name'); - $validation->required('full_name'); - } elsif ( $user->type eq 'organisation' ) { - $validation->required('name'); - $validation->required('street_name'); - $validation->required('town'); - $validation->required('sector'); - } - - return $c->api_validation_error if $validation->has_error; - - my $location = $c->get_location_from_postcode( - $validation->param('postcode'), - $user->type, - ); - - if ( $user->type eq 'customer' ){ - - $c->schema->txn_do( sub { - $user->entity->customer->update({ - full_name => $validation->param('full_name'), - display_name => $validation->param('display_name'), - postcode => $validation->param('postcode'), - ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), - }); - $user->update({ - email => $validation->param('email'), - ( defined $validation->param('new_password') ? ( password => $validation->param('new_password') ) : () ), - }); - }); - - } - elsif ( $user->type eq 'organisation' ) { - - $c->schema->txn_do( sub { - $user->entity->organisation->update({ - name => $validation->param('name'), - street_name => $validation->param('street_name'), - town => $validation->param('town'), - sector => $validation->param('sector'), - postcode => $validation->param('postcode'), - ( defined $location ? ( %$location ) : ( latitude => undef, longitude => undef ) ), - }); - $user->update({ - email => $validation->param('email'), - ( defined $validation->param('new_password') ? ( password => $validation->param('new_password') ) : () ), - }); - }); - } - - return $c->render( json => { - success => Mojo::JSON->true, - message => 'Edited Account Successfully', - }); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer.pm index bb5623c..4981019 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer.pm @@ -2,20 +2,20 @@ package Pear::LocalLoop::Controller::Api::V1::Customer; use Mojo::Base 'Mojolicious::Controller'; sub auth { - my $c = shift; + my $c = shift; - return 1 if $c->stash->{api_user}->type eq 'customer'; + return 1 if $c->stash->{api_user}->type eq 'customer'; - $c->render( - json => { - success => Mojo::JSON->false, - message => 'Not an Customer', - error => 'user_not_cust', - }, - status => 403, - ); + $c->render( + json => { + success => Mojo::JSON->false, + message => 'Not an Customer', + error => 'user_not_cust', + }, + status => 403, + ); - return 0; + return 0; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm index 2f8e4fc..5e927ac 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm @@ -2,166 +2,174 @@ package Pear::LocalLoop::Controller::Api::V1::Customer::Graphs; use Mojo::Base 'Mojolicious::Controller'; has error_messages => sub { - return { - graph => { - required => { message => 'Must request graph type', status => 400 }, - in => { message => 'Unrecognised graph type', status => 400 }, - }, - }; + return { + graph => { + required => { message => 'Must request graph type', status => 400 }, + in => { message => 'Unrecognised graph type', status => 400 }, + }, + }; }; sub index { - my $c = shift; + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->required('graph')->in( + qw/ + total_last_week + avg_spend_last_week + total_last_month + avg_spend_last_month + / + ); - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - $validation->required('graph')->in( qw/ - total_last_week - avg_spend_last_week - total_last_month - avg_spend_last_month - / ); + return $c->api_validation_error if $validation->has_error; - return $c->api_validation_error if $validation->has_error; + my $graph_sub = "graph_" . $validation->param('graph'); - my $graph_sub = "graph_" . $validation->param('graph'); + unless ( $c->can($graph_sub) ) { - unless ( $c->can($graph_sub) ) { - # Secondary catch in case a mistake has been made - return $c->render( - json => { - success => Mojo::JSON->false, - message => $c->error_messages->{graph}->{in}->{message}, - error => 'in', - }, - status => $c->error_messages->{graph}->{in}->{status}, - ); - } + # Secondary catch in case a mistake has been made + return $c->render( + json => { + success => Mojo::JSON->false, + message => $c->error_messages->{graph}->{in}->{message}, + error => 'in', + }, + status => $c->error_messages->{graph}->{in}->{status}, + ); + } - return $c->$graph_sub; + return $c->$graph_sub; } -sub graph_total_last_week { return shift->_purchases_total_duration( 7 ) } -sub graph_total_last_month { return shift->_purchases_total_duration( 30 ) } +sub graph_total_last_week { return shift->_purchases_total_duration(7) } +sub graph_total_last_month { return shift->_purchases_total_duration(30) } sub _purchases_total_duration { - my ( $c, $day_duration ) = @_; - - my $duration = DateTime::Duration->new( days => $day_duration ); - my $entity = $c->stash->{api_user}->entity; - - my $data = { labels => [], data => [] }; - - my ( $start, $end ) = $c->_get_start_end_duration( $duration ); - - $data->{bounds} = { - min => $c->format_iso_datetime( $start ), - max => $c->format_iso_datetime( $end ), - }; - - while ( $start < $end ) { - my $next_end = $start->clone->add( days => 1 ); - my $transactions = $entity->purchases - ->search_between( $start, $next_end ) - ->get_column('value') - ->sum || 0 * 1; - push @{ $data->{ labels } }, $c->format_iso_datetime( $start ); - push @{ $data->{ data } }, $transactions / 100000; - $start->add( days => 1 ); - } - - return $c->render( - json => { - success => Mojo::JSON->true, - graph => $data, + my ( $c, $day_duration ) = @_; + + my $duration = DateTime::Duration->new( days => $day_duration ); + my $entity = $c->stash->{api_user}->entity; + + my $data = { labels => [], data => [] }; + + my ( $start, $end ) = $c->_get_start_end_duration($duration); + + $data->{bounds} = { + min => $c->format_iso_datetime($start), + max => $c->format_iso_datetime($end), + }; + + while ( $start < $end ) { + my $next_end = $start->clone->add( days => 1 ); + my $transactions = + $entity->purchases->search_between( $start, $next_end ) + ->get_column('value')->sum || 0 * 1; + push @{ $data->{labels} }, $c->format_iso_datetime($start); + push @{ $data->{data} }, $transactions / 100000; + $start->add( days => 1 ); } - ); + + return $c->render( + json => { + success => Mojo::JSON->true, + graph => $data, + } + ); } -sub graph_avg_spend_last_week { return shift->_purchases_avg_spend_duration( 7 ) } -sub graph_avg_spend_last_month { return shift->_purchases_avg_spend_duration( 30 ) } +sub graph_avg_spend_last_week { return shift->_purchases_avg_spend_duration(7) } + +sub graph_avg_spend_last_month { + return shift->_purchases_avg_spend_duration(30); +} sub _purchases_avg_spend_duration { - my ( $c, $day_duration ) = @_; - - my $duration = DateTime::Duration->new( days => $day_duration ); - my $entity = $c->stash->{api_user}->entity; - - my $data = { labels => [], data => [] }; - - my ( $start, $end ) = $c->_get_start_end_duration( $duration ); - - $data->{bounds} = { - min => $c->format_iso_datetime( $start ), - max => $c->format_iso_datetime( $end ), - }; - - my $dtf = $c->schema->storage->datetime_parser; - my $driver = $c->schema->storage->dbh->{Driver}->{Name}; - my $transaction_rs = $c->schema->resultset('ViewQuantisedTransaction' . $driver)->search( - { - purchase_time => { - -between => [ - $dtf->format_datetime($start), - $dtf->format_datetime($end), - ], - }, - buyer_id => $entity->id, - }, - { - columns => [ + my ( $c, $day_duration ) = @_; + + my $duration = DateTime::Duration->new( days => $day_duration ); + my $entity = $c->stash->{api_user}->entity; + + my $data = { labels => [], data => [] }; + + my ( $start, $end ) = $c->_get_start_end_duration($duration); + + $data->{bounds} = { + min => $c->format_iso_datetime($start), + max => $c->format_iso_datetime($end), + }; + + my $dtf = $c->schema->storage->datetime_parser; + my $driver = $c->schema->storage->dbh->{Driver}->{Name}; + my $transaction_rs = + $c->schema->resultset( 'ViewQuantisedTransaction' . $driver )->search( { - quantised => 'quantised_days', - count => \"COUNT(*)", - sum_value => $c->pg_or_sqlite( - 'SUM("me"."value")', - 'SUM("me"."value")', - ), - average_value => $c->pg_or_sqlite( - 'AVG("me"."value")', - 'AVG("me"."value")', - ), + purchase_time => { + -between => [ + $dtf->format_datetime($start), + $dtf->format_datetime($end), + ], + }, + buyer_id => $entity->id, + }, + { + columns => [ + { + quantised => 'quantised_days', + count => \"COUNT(*)", + sum_value => $c->pg_or_sqlite( + 'SUM("me"."value")', 'SUM("me"."value")', + ), + average_value => $c->pg_or_sqlite( + 'AVG("me"."value")', 'AVG("me"."value")', + ), + } + ], + group_by => 'quantised_days', + order_by => { '-asc' => 'quantised_days' }, } - ], - group_by => 'quantised_days', - order_by => { '-asc' => 'quantised_days' }, - } - ); - - for ( $transaction_rs->all ) { - my $quantised = $c->db_datetime_parser->parse_datetime($_->get_column('quantised')); - push @{ $data->{ labels } }, $c->format_iso_datetime( $quantised ); - push @{ $data->{ data } }, ($_->get_column('average_value') || 0) / 100000; - } - - return $c->render( - json => { - success => Mojo::JSON->true, - graph => $data, + ); + + for ( $transaction_rs->all ) { + my $quantised = + $c->db_datetime_parser->parse_datetime( $_->get_column('quantised') ); + push @{ $data->{labels} }, $c->format_iso_datetime($quantised); + push @{ $data->{data} }, + ( $_->get_column('average_value') || 0 ) / 100000; } - ); + + return $c->render( + json => { + success => Mojo::JSON->true, + graph => $data, + } + ); } sub _get_start_end_duration { - my ( $c, $duration ) = @_; - my $end = DateTime->today; - my $start = $end->clone->subtract_duration( $duration ); - return ( $start, $end ); + my ( $c, $duration ) = @_; + my $end = DateTime->today; + my $start = $end->clone->subtract_duration($duration); + return ( $start, $end ); } 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; - } + 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; + } } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm index 353ab06..30e2123 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm @@ -2,61 +2,68 @@ package Pear::LocalLoop::Controller::Api::V1::Customer::Pies; use Mojo::Base 'Mojolicious::Controller'; sub index { - my $c = shift; - - my $entity = $c->stash->{api_user}->entity; - - my $purchase_rs = $entity->purchases; - - my $local_org_local_purchase = $purchase_rs->search({ - "me.distance" => { '<', 20000 }, - 'organisation.is_local' => 1, - }, - { - join => { 'seller' => 'organisation' }, - } - ); - - my $local_org_non_local_purchase = $purchase_rs->search({ - "me.distance" => { '>=', 20000 }, - 'organisation.is_local' => 1, - }, - { - join => { 'seller' => 'organisation' }, - } - ); - - my $non_local_org_local_purchase = $purchase_rs->search({ - "me.distance" => { '<', 20000 }, - 'organisation.is_local' => 0, - }, - { - join => { 'seller' => 'organisation' }, - } - ); - - my $non_local_org_non_local_purchase = $purchase_rs->search({ - "me.distance" => { '>=', 20000 }, - 'organisation.is_local' => 0, - }, - { - join => { 'seller' => 'organisation' }, - } - ); - - 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, - }; - - return $c->render( - json => { - success => Mojo::JSON->true, - local_all => $local_all, - } - ); + my $c = shift; + + my $entity = $c->stash->{api_user}->entity; + + my $purchase_rs = $entity->purchases; + + my $local_org_local_purchase = $purchase_rs->search( + { + "me.distance" => { '<', 20000 }, + 'organisation.is_local' => 1, + }, + { + join => { 'seller' => 'organisation' }, + } + ); + + my $local_org_non_local_purchase = $purchase_rs->search( + { + "me.distance" => { '>=', 20000 }, + 'organisation.is_local' => 1, + }, + { + join => { 'seller' => 'organisation' }, + } + ); + + my $non_local_org_local_purchase = $purchase_rs->search( + { + "me.distance" => { '<', 20000 }, + 'organisation.is_local' => 0, + }, + { + join => { 'seller' => 'organisation' }, + } + ); + + my $non_local_org_non_local_purchase = $purchase_rs->search( + { + "me.distance" => { '>=', 20000 }, + 'organisation.is_local' => 0, + }, + { + join => { 'seller' => 'organisation' }, + } + ); + + 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, + }; + + return $c->render( + json => { + success => Mojo::JSON->true, + local_all => $local_all, + } + ); } diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm index 139b796..a7daca2 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm @@ -2,30 +2,33 @@ package Pear::LocalLoop::Controller::Api::V1::Customer::Snippets; use Mojo::Base 'Mojolicious::Controller'; sub index { - my $c = shift; + my $c = shift; - my $entity = $c->stash->{api_user}->entity; - my $data = { - user_sum => 0, - user_position => 0, - }; + my $entity = $c->stash->{api_user}->entity; + my $data = { + user_sum => 0, + user_position => 0, + }; - my $user_rs = $entity->purchases; - $data->{ user_sum } = $user_rs->get_column('value')->sum || 0; - $data->{ user_sum } /= 100000; + my $user_rs = $entity->purchases; + $data->{user_sum} = $user_rs->get_column('value')->sum || 0; + $data->{user_sum} /= 100000; - my $leaderboard_rs = $c->schema->resultset('Leaderboard'); - my $monthly_board = $leaderboard_rs->get_latest( 'monthly_total' ); - if (defined $monthly_board) { - my $monthly_values = $monthly_board->values; - $data->{ user_position } = $monthly_values ? $monthly_values->find({ entity_id => $entity->id })->position : 0; - } - return $c->render( - json => { - success => Mojo::JSON->true, - snippets => $data, + my $leaderboard_rs = $c->schema->resultset('Leaderboard'); + my $monthly_board = $leaderboard_rs->get_latest('monthly_total'); + if ( defined $monthly_board ) { + my $monthly_values = $monthly_board->values; + $data->{user_position} = + $monthly_values + ? $monthly_values->find( { entity_id => $entity->id } )->position + : 0; } - ); + return $c->render( + json => { + success => Mojo::JSON->true, + snippets => $data, + } + ); } diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation.pm index 29a3ccb..a2abc17 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation.pm @@ -2,20 +2,20 @@ package Pear::LocalLoop::Controller::Api::V1::Organisation; use Mojo::Base 'Mojolicious::Controller'; sub auth { - my $c = shift; + my $c = shift; - return 1 if $c->stash->{api_user}->type eq 'organisation'; + return 1 if $c->stash->{api_user}->type eq 'organisation'; - $c->render( - json => { - success => Mojo::JSON->false, - message => 'Not an Organisation', - error => 'user_not_org', - }, - status => 403, - ); + $c->render( + json => { + success => Mojo::JSON->false, + message => 'Not an Organisation', + error => 'user_not_org', + }, + status => 403, + ); - return 0; + return 0; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm index a6f56eb..5108804 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm @@ -2,197 +2,195 @@ package Pear::LocalLoop::Controller::Api::V1::Organisation::Graphs; use Mojo::Base 'Mojolicious::Controller'; has error_messages => sub { - return { - graph => { - required => { message => 'Must request graph type', status => 400 }, - in => { message => 'Unrecognised graph type', status => 400 }, - }, - }; + return { + graph => { + required => { message => 'Must request graph type', status => 400 }, + in => { message => 'Unrecognised graph type', status => 400 }, + }, + }; }; sub index { - my $c = shift; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - $validation->required('graph')->in( qw/ - customers_last_7_days - customers_last_30_days - sales_last_7_days - sales_last_30_days - purchases_last_7_days - purchases_last_30_days - customers_range - / ); - - return $c->api_validation_error if $validation->has_error; - - my $graph_sub = "graph_" . $validation->param('graph'); - - unless ( $c->can($graph_sub) ) { - # Secondary catch in case a mistake has been made - return $c->render( - json => { - success => Mojo::JSON->false, - message => $c->error_messages->{graph}->{in}->{message}, - error => 'in', - }, - status => $c->error_messages->{graph}->{in}->{status}, + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->required('graph')->in( + qw/ + customers_last_7_days + customers_last_30_days + sales_last_7_days + sales_last_30_days + purchases_last_7_days + purchases_last_30_days + customers_range + / ); - } - return $c->$graph_sub; + return $c->api_validation_error if $validation->has_error; + + my $graph_sub = "graph_" . $validation->param('graph'); + + unless ( $c->can($graph_sub) ) { + + # Secondary catch in case a mistake has been made + return $c->render( + json => { + success => Mojo::JSON->false, + message => $c->error_messages->{graph}->{in}->{message}, + error => 'in', + }, + status => $c->error_messages->{graph}->{in}->{status}, + ); + } + + return $c->$graph_sub; } sub graph_customers_range { - my $c = shift; - - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - $validation->required('start')->is_iso_date; - $validation->required('end')->is_iso_date; - - return $c->api_validation_error if $validation->has_error; - - my $entity = $c->stash->{api_user}->entity; - - my $data = { labels => [], data => [] }; - my $start = $c->parse_iso_date( $validation->param('start') ); - my $end = $c->parse_iso_date( $validation->param('end') ); - - while ( $start <= $end ) { - my $next_end = $start->clone->add( days => 1 ); - my $transactions = $entity->sales - ->search_between( $start, $next_end ) - ->count; - push @{ $data->{ labels } }, $c->format_iso_date( $start ); - push @{ $data->{ data } }, $transactions; - $start->add( days => 1 ); - } - - return $c->render( - json => { - success => Mojo::JSON->true, - graph => $data, + my $c = shift; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->required('start')->is_iso_date; + $validation->required('end')->is_iso_date; + + return $c->api_validation_error if $validation->has_error; + + my $entity = $c->stash->{api_user}->entity; + + my $data = { labels => [], data => [] }; + my $start = $c->parse_iso_date( $validation->param('start') ); + my $end = $c->parse_iso_date( $validation->param('end') ); + + while ( $start <= $end ) { + my $next_end = $start->clone->add( days => 1 ); + my $transactions = + $entity->sales->search_between( $start, $next_end )->count; + push @{ $data->{labels} }, $c->format_iso_date($start); + push @{ $data->{data} }, $transactions; + $start->add( days => 1 ); } - ); + + return $c->render( + json => { + success => Mojo::JSON->true, + graph => $data, + } + ); } -sub graph_customers_last_7_days { return shift->_customers_last_duration( 7 ) } -sub graph_customers_last_30_days { return shift->_customers_last_duration( 30 ) } +sub graph_customers_last_7_days { return shift->_customers_last_duration(7) } +sub graph_customers_last_30_days { return shift->_customers_last_duration(30) } sub _customers_last_duration { - my ( $c, $day_duration ) = @_; - - my $duration = DateTime::Duration->new( days => $day_duration ); - my $entity = $c->stash->{api_user}->entity; - - my $data = { labels => [], data => [] }; - - my ( $start, $end ) = $c->_get_start_end_duration( $duration ); - - $data->{bounds} = { - min => $c->format_iso_datetime( $start ), - max => $c->format_iso_datetime( $end ), - }; - - while ( $start < $end ) { - my $next_end = $start->clone->add( days => 1 ); - my $transactions = $entity->sales - ->search_between( $start, $next_end ) - ->count; - push @{ $data->{ labels } }, $c->format_iso_datetime( $start ); - push @{ $data->{ data } }, $transactions; - $start->add( days => 1 ); - } - - return $c->render( - json => { - success => Mojo::JSON->true, - graph => $data, + my ( $c, $day_duration ) = @_; + + my $duration = DateTime::Duration->new( days => $day_duration ); + my $entity = $c->stash->{api_user}->entity; + + my $data = { labels => [], data => [] }; + + my ( $start, $end ) = $c->_get_start_end_duration($duration); + + $data->{bounds} = { + min => $c->format_iso_datetime($start), + max => $c->format_iso_datetime($end), + }; + + while ( $start < $end ) { + my $next_end = $start->clone->add( days => 1 ); + my $transactions = + $entity->sales->search_between( $start, $next_end )->count; + push @{ $data->{labels} }, $c->format_iso_datetime($start); + push @{ $data->{data} }, $transactions; + $start->add( days => 1 ); } - ); + + return $c->render( + json => { + success => Mojo::JSON->true, + graph => $data, + } + ); } -sub graph_sales_last_7_days { return shift->_sales_last_duration( 7 ) } -sub graph_sales_last_30_days { return shift->_sales_last_duration( 30 ) } +sub graph_sales_last_7_days { return shift->_sales_last_duration(7) } +sub graph_sales_last_30_days { return shift->_sales_last_duration(30) } sub _sales_last_duration { - my ( $c, $day_duration ) = @_; - - my $duration = DateTime::Duration->new( days => $day_duration ); - my $entity = $c->stash->{api_user}->entity; - - my $data = { labels => [], data => [] }; - - my ( $start, $end ) = $c->_get_start_end_duration( $duration ); - - $data->{bounds} = { - min => $c->format_iso_datetime( $start ), - max => $c->format_iso_datetime( $end ), - }; - - while ( $start < $end ) { - my $next_end = $start->clone->add( days => 1 ); - my $transactions = $entity->sales - ->search_between( $start, $next_end ) - ->get_column('value') - ->sum || 0 + 0; - push @{ $data->{ labels } }, $c->format_iso_datetime( $start ); - push @{ $data->{ data } }, $transactions / 100000; - $start->add( days => 1 ); - } - - return $c->render( - json => { - success => Mojo::JSON->true, - graph => $data, + my ( $c, $day_duration ) = @_; + + my $duration = DateTime::Duration->new( days => $day_duration ); + my $entity = $c->stash->{api_user}->entity; + + my $data = { labels => [], data => [] }; + + my ( $start, $end ) = $c->_get_start_end_duration($duration); + + $data->{bounds} = { + min => $c->format_iso_datetime($start), + max => $c->format_iso_datetime($end), + }; + + while ( $start < $end ) { + my $next_end = $start->clone->add( days => 1 ); + my $transactions = $entity->sales->search_between( $start, $next_end ) + ->get_column('value')->sum || 0 + 0; + push @{ $data->{labels} }, $c->format_iso_datetime($start); + push @{ $data->{data} }, $transactions / 100000; + $start->add( days => 1 ); } - ); + + return $c->render( + json => { + success => Mojo::JSON->true, + graph => $data, + } + ); } -sub graph_purchases_last_7_days { return shift->_purchases_last_duration( 7 ) } -sub graph_purchases_last_30_days { return shift->_purchases_last_duration( 30 ) } +sub graph_purchases_last_7_days { return shift->_purchases_last_duration(7) } +sub graph_purchases_last_30_days { return shift->_purchases_last_duration(30) } sub _purchases_last_duration { - my ( $c, $day_duration ) = @_; - - my $duration = DateTime::Duration->new( days => $day_duration ); - my $entity = $c->stash->{api_user}->entity; - - my $data = { labels => [], data => [] }; - - my ( $start, $end ) = $c->_get_start_end_duration( $duration ); - - $data->{bounds} = { - min => $c->format_iso_datetime( $start ), - max => $c->format_iso_datetime( $end ), - }; - - while ( $start < $end ) { - my $next_end = $start->clone->add( days => 1 ); - my $transactions = $entity->purchases - ->search_between( $start, $next_end ) - ->get_column('value') - ->sum || 0 + 0; - push @{ $data->{ labels } }, $c->format_iso_datetime( $start ); - push @{ $data->{ data } }, $transactions / 100000; - $start->add( days => 1 ); - } - - return $c->render( - json => { - success => Mojo::JSON->true, - graph => $data, + my ( $c, $day_duration ) = @_; + + my $duration = DateTime::Duration->new( days => $day_duration ); + my $entity = $c->stash->{api_user}->entity; + + my $data = { labels => [], data => [] }; + + my ( $start, $end ) = $c->_get_start_end_duration($duration); + + $data->{bounds} = { + min => $c->format_iso_datetime($start), + max => $c->format_iso_datetime($end), + }; + + while ( $start < $end ) { + my $next_end = $start->clone->add( days => 1 ); + my $transactions = + $entity->purchases->search_between( $start, $next_end ) + ->get_column('value')->sum || 0 + 0; + push @{ $data->{labels} }, $c->format_iso_datetime($start); + push @{ $data->{data} }, $transactions / 100000; + $start->add( days => 1 ); } - ); + + return $c->render( + json => { + success => Mojo::JSON->true, + graph => $data, + } + ); } sub _get_start_end_duration { - my ( $c, $duration ) = @_; - my $end = DateTime->today; - my $start = $end->clone->subtract_duration( $duration ); - return ( $start, $end ); + my ( $c, $duration ) = @_; + my $end = DateTime->today; + my $start = $end->clone->subtract_duration($duration); + return ( $start, $end ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Pies.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Pies.pm index e336a44..f554618 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Pies.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Pies.pm @@ -2,61 +2,68 @@ package Pear::LocalLoop::Controller::Api::V1::Organisation::Pies; use Mojo::Base 'Mojolicious::Controller'; sub index { - my $c = shift; - - my $entity = $c->stash->{api_user}->entity; - - my $purchase_rs = $entity->purchases; - - my $local_org_local_purchase = $purchase_rs->search({ - "me.distance" => { '<', 20000 }, - 'organisation.is_local' => 1, - }, - { - join => { 'seller' => 'organisation' }, - } - ); - - my $local_org_non_local_purchase = $purchase_rs->search({ - "me.distance" => { '>=', 20000 }, - 'organisation.is_local' => 1, - }, - { - join => { 'seller' => 'organisation' }, - } - ); - - my $non_local_org_local_purchase = $purchase_rs->search({ - "me.distance" => { '<', 20000 }, - 'organisation.is_local' => [0, undef], - }, - { - join => { 'seller' => 'organisation' }, - } - ); - - my $non_local_org_non_local_purchase = $purchase_rs->search({ - "me.distance" => { '>=', 20000 }, - 'organisation.is_local' => [0, undef], - }, - { - join => { 'seller' => 'organisation' }, - } - ); - - 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, - }; - - return $c->render( - json => { - success => Mojo::JSON->true, - local_all => $local_all, - } - ); + my $c = shift; + + my $entity = $c->stash->{api_user}->entity; + + my $purchase_rs = $entity->purchases; + + my $local_org_local_purchase = $purchase_rs->search( + { + "me.distance" => { '<', 20000 }, + 'organisation.is_local' => 1, + }, + { + join => { 'seller' => 'organisation' }, + } + ); + + my $local_org_non_local_purchase = $purchase_rs->search( + { + "me.distance" => { '>=', 20000 }, + 'organisation.is_local' => 1, + }, + { + join => { 'seller' => 'organisation' }, + } + ); + + my $non_local_org_local_purchase = $purchase_rs->search( + { + "me.distance" => { '<', 20000 }, + 'organisation.is_local' => [ 0, undef ], + }, + { + join => { 'seller' => 'organisation' }, + } + ); + + my $non_local_org_non_local_purchase = $purchase_rs->search( + { + "me.distance" => { '>=', 20000 }, + 'organisation.is_local' => [ 0, undef ], + }, + { + join => { 'seller' => 'organisation' }, + } + ); + + 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, + }; + + return $c->render( + json => { + success => Mojo::JSON->true, + local_all => $local_all, + } + ); } diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm index f86dc7f..ddc5fe4 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm @@ -2,80 +2,87 @@ package Pear::LocalLoop::Controller::Api::V1::Organisation::Snippets; use Mojo::Base 'Mojolicious::Controller'; sub index { - my $c = shift; + my $c = shift; - my $entity = $c->stash->{api_user}->entity; - my $data = { - all_sales_count => 0, - all_sales_total => 0, - all_purchases_count => 0, - all_purchases_total => 0, - this_month_sales_count => 0, - this_month_sales_total => 0, - this_month_purchases_count => 0, - this_month_purchases_total => 0, - this_week_sales_count => 0, - this_week_sales_total => 0, - this_week_purchases_count => 0, - this_week_purchases_total => 0, - today_sales_count => 0, - today_sales_total => 0, - today_purchases_count => 0, - today_purchases_total => 0, - }; + my $entity = $c->stash->{api_user}->entity; + my $data = { + all_sales_count => 0, + all_sales_total => 0, + all_purchases_count => 0, + all_purchases_total => 0, + this_month_sales_count => 0, + this_month_sales_total => 0, + this_month_purchases_count => 0, + this_month_purchases_total => 0, + this_week_sales_count => 0, + this_week_sales_total => 0, + this_week_purchases_count => 0, + this_week_purchases_total => 0, + today_sales_count => 0, + today_sales_total => 0, + today_purchases_count => 0, + today_purchases_total => 0, + }; - my $now = DateTime->now; - my $today = DateTime->today; - my $week_ago = $today->clone->subtract( days => 7 ); - my $month_ago = $today->clone->subtract( days => 30 ); + my $now = DateTime->now; + my $today = DateTime->today; + my $week_ago = $today->clone->subtract( days => 7 ); + my $month_ago = $today->clone->subtract( days => 30 ); - # TODO check that sales is doing the right thing here - my $all_sales = $entity->sales; - $data->{ all_sales_count } = $all_sales->count; - $data->{ all_sales_total } = $all_sales->get_column('value')->sum || 0; - $data->{ all_sales_total } /= 100000; + # TODO check that sales is doing the right thing here + my $all_sales = $entity->sales; + $data->{all_sales_count} = $all_sales->count; + $data->{all_sales_total} = $all_sales->get_column('value')->sum || 0; + $data->{all_sales_total} /= 100000; - my $today_sales = $entity->sales->search_between( $today, $now ); - $data->{ today_sales_count } = $today_sales->count; - $data->{ today_sales_total } = $today_sales->get_column('value')->sum || 0; - $data->{ today_sales_total } /= 100000; + my $today_sales = $entity->sales->search_between( $today, $now ); + $data->{today_sales_count} = $today_sales->count; + $data->{today_sales_total} = $today_sales->get_column('value')->sum || 0; + $data->{today_sales_total} /= 100000; - my $week_sales = $entity->sales->search_between( $week_ago, $today ); - $data->{ this_week_sales_count } = $week_sales->count; - $data->{ this_week_sales_total } = $week_sales->get_column('value')->sum || 0; - $data->{ this_week_sales_total } /= 100000; + my $week_sales = $entity->sales->search_between( $week_ago, $today ); + $data->{this_week_sales_count} = $week_sales->count; + $data->{this_week_sales_total} = $week_sales->get_column('value')->sum || 0; + $data->{this_week_sales_total} /= 100000; - my $month_sales = $entity->sales->search_between( $month_ago, $today ); - $data->{ this_month_sales_count } = $month_sales->count; - $data->{ this_month_sales_total } = $month_sales->get_column('value')->sum || 0; - $data->{ this_month_sales_total } /= 100000; + my $month_sales = $entity->sales->search_between( $month_ago, $today ); + $data->{this_month_sales_count} = $month_sales->count; + $data->{this_month_sales_total} = + $month_sales->get_column('value')->sum || 0; + $data->{this_month_sales_total} /= 100000; - my $all_purchases = $entity->purchases; - $data->{ all_purchases_count } = $all_purchases->count; - $data->{ all_purchases_total } = $all_purchases->get_column('value')->sum || 0; - $data->{ all_purchases_total } /= 100000; + my $all_purchases = $entity->purchases; + $data->{all_purchases_count} = $all_purchases->count; + $data->{all_purchases_total} = + $all_purchases->get_column('value')->sum || 0; + $data->{all_purchases_total} /= 100000; - my $today_purchases = $entity->purchases->search_between( $today, $now ); - $data->{ today_purchases_count } = $today_purchases->count; - $data->{ today_purchases_total } = $today_purchases->get_column('value')->sum || 0; - $data->{ today_purchases_total } /= 100000; + my $today_purchases = $entity->purchases->search_between( $today, $now ); + $data->{today_purchases_count} = $today_purchases->count; + $data->{today_purchases_total} = + $today_purchases->get_column('value')->sum || 0; + $data->{today_purchases_total} /= 100000; - my $week_purchases = $entity->purchases->search_between( $week_ago, $today ); - $data->{ this_week_purchases_count } = $week_purchases->count; - $data->{ this_week_purchases_total } = $week_purchases->get_column('value')->sum || 0; - $data->{ this_week_purchases_total } /= 100000; + my $week_purchases = + $entity->purchases->search_between( $week_ago, $today ); + $data->{this_week_purchases_count} = $week_purchases->count; + $data->{this_week_purchases_total} = + $week_purchases->get_column('value')->sum || 0; + $data->{this_week_purchases_total} /= 100000; - my $month_purchases = $entity->purchases->search_between( $month_ago, $today ); - $data->{ this_month_purchases_count } = $month_purchases->count; - $data->{ this_month_purchases_total } = $month_purchases->get_column('value')->sum || 0; - $data->{ this_month_purchases_total } /= 100000; + my $month_purchases = + $entity->purchases->search_between( $month_ago, $today ); + $data->{this_month_purchases_count} = $month_purchases->count; + $data->{this_month_purchases_total} = + $month_purchases->get_column('value')->sum || 0; + $data->{this_month_purchases_total} /= 100000; - return $c->render( - json => { - success => Mojo::JSON->true, - snippets => $data, - } - ); + return $c->render( + json => { + success => Mojo::JSON->true, + snippets => $data, + } + ); } diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm index c90539b..6199372 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm @@ -2,192 +2,208 @@ package Pear::LocalLoop::Controller::Api::V1::Supplier::Location; use Mojo::Base 'Mojolicious::Controller'; has validation_data => sub { - my $children_errors = { - latitude => { - validation => [ - { required => {} }, - { number => { error_prefix => 'not_number' } }, - { in_range => { args => [ -90, 90 ], error_prefix => 'outside_range' } }, - ], - }, - longitude => { - validation => [ - { required => {} }, - { number => { error_prefix => 'not_number' } }, - { in_range => { args => [ -180, 180 ], error_prefix => 'outside_range' } }, - ], - }, - }; - - return { - index => { - north_east => { - validation => [ - { required => {} }, - { is_object => { error_prefix => 'not_object' } }, - ], - children => $children_errors, - }, - south_west => { - validation => [ - { required => {} }, - { is_object => { error_prefix => 'not_object' } }, - ], - children => $children_errors, - }, - } - } + my $children_errors = { + latitude => { + validation => [ + { required => {} }, + { number => { error_prefix => 'not_number' } }, + { + in_range => + { args => [ -90, 90 ], error_prefix => 'outside_range' } + }, + ], + }, + longitude => { + validation => [ + { required => {} }, + { number => { error_prefix => 'not_number' } }, + { + in_range => { + args => [ -180, 180 ], + error_prefix => 'outside_range' + } + }, + ], + }, + }; + + return { + index => { + north_east => { + validation => [ + { required => {} }, + { is_object => { error_prefix => 'not_object' } }, + ], + children => $children_errors, + }, + south_west => { + validation => [ + { required => {} }, + { is_object => { error_prefix => 'not_object' } }, + ], + children => $children_errors, + }, + } + }; }; sub index { - my $c = shift; + my $c = shift; - return if $c->validation_error('index'); + return if $c->validation_error('index'); - my $json = $c->stash->{api_json}; + my $json = $c->stash->{api_json}; - # Extra custom error, because its funny - if ( $json->{north_east}->{latitude} < $json->{south_west}->{latitude} ) { - return $c->render( - json => { - success => Mojo::JSON->false, - errors => [ 'upside_down' ], - }, - status => 400, - ); - } - - my $entity = $c->stash->{api_user}->entity; - my $entity_type_object = $entity->type_object; - - # need: organisations only, with name, latitude, and longitude - my $org_rs = $entity->purchases->search_related('seller', - { - 'seller.type' => 'organisation', - 'organisation.latitude' => { -between => [ - $json->{south_west}->{latitude}, - $json->{north_east}->{latitude}, - ] }, - 'organisation.longitude' => { -between => [ - $json->{south_west}->{longitude}, - $json->{north_east}->{longitude}, - ] }, - }, - { - join => [ qw/ organisation / ], - columns => [ - 'organisation.name', - 'organisation.latitude', - 'organisation.longitude', - 'organisation.street_name', - 'organisation.town', - 'organisation.postcode', - ], - group_by => [ qw/ organisation.id / ], - }, - ); - - $org_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); - - my $suppliers = [ map { - { - latitude => $_->{organisation}->{latitude} * 1, - longitude => $_->{organisation}->{longitude} * 1, - name => $_->{organisation}->{name}, - street_name => $_->{organisation}->{street_name}, - town => $_->{organisation}->{town}, - postcode => $_->{organisation}->{postcode}, + # Extra custom error, because its funny + if ( $json->{north_east}->{latitude} < $json->{south_west}->{latitude} ) { + return $c->render( + json => { + success => Mojo::JSON->false, + errors => ['upside_down'], + }, + status => 400, + ); } - } $org_rs->all ]; - - $c->render( - json => { - success => Mojo::JSON->true, - suppliers => $suppliers, - self => { - latitude => $entity_type_object->latitude, - longitude => $entity_type_object->longitude, - } - }, - ); + + my $entity = $c->stash->{api_user}->entity; + my $entity_type_object = $entity->type_object; + + # need: organisations only, with name, latitude, and longitude + my $org_rs = $entity->purchases->search_related( + 'seller', + { + 'seller.type' => 'organisation', + 'organisation.latitude' => { + -between => [ + $json->{south_west}->{latitude}, + $json->{north_east}->{latitude}, + ] + }, + 'organisation.longitude' => { + -between => [ + $json->{south_west}->{longitude}, + $json->{north_east}->{longitude}, + ] + }, + }, + { + join => [qw/ organisation /], + columns => [ + 'organisation.name', 'organisation.latitude', + 'organisation.longitude', 'organisation.street_name', + 'organisation.town', 'organisation.postcode', + ], + group_by => [qw/ organisation.id /], + }, + ); + + $org_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); + + my $suppliers = [ + map { + { + latitude => $_->{organisation}->{latitude} * 1, + longitude => $_->{organisation}->{longitude} * 1, + name => $_->{organisation}->{name}, + street_name => $_->{organisation}->{street_name}, + town => $_->{organisation}->{town}, + postcode => $_->{organisation}->{postcode}, + } + } $org_rs->all + ]; + + $c->render( + json => { + success => Mojo::JSON->true, + suppliers => $suppliers, + self => { + latitude => $entity_type_object->latitude, + longitude => $entity_type_object->longitude, + } + }, + ); } sub trail_load { - my $c = shift; + my $c = shift; - return if $c->validation_error('index'); + return if $c->validation_error('index'); - my $json = $c->stash->{api_json}; + my $json = $c->stash->{api_json}; - # Extra custom error, because its funny - if ( $json->{north_east}->{latitude} < $json->{south_west}->{latitude} ) { - return $c->render( - json => { - success => Mojo::JSON->false, - errors => [ 'upside_down' ], - }, - status => 400, - ); - } - - my $entity = $c->stash->{api_user}->entity; - my $entity_type_object = $entity->type_object; - my $orgs_lis = $c->schema->resultset('EntityAssociation')->search( - { - $json->{association} => 1, - }, - ); - - # need: organisations only, with name, latitude, and longitude - my $org_rs = $orgs_lis->search_related('entity', - { - 'entity.type' => 'organisation', - 'organisation.latitude' => { -between => [ - $json->{south_west}->{latitude}, - $json->{north_east}->{latitude}, - ] }, - 'organisation.longitude' => { -between => [ - $json->{south_west}->{longitude}, - $json->{north_east}->{longitude}, - ] }, - }, - { - join => [ qw/ organisation / ], - columns => [ - 'organisation.name', - 'organisation.latitude', - 'organisation.longitude', - 'organisation.street_name', - 'organisation.town', - 'organisation.postcode', - ], - group_by => [ qw/ organisation.id / ], - }, - ); - - $org_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); - - my $locations = [ map { - { - latitude => $_->{organisation}->{latitude} * 1, - longitude => $_->{organisation}->{longitude} * 1, - name => $_->{organisation}->{name}, - street_name => $_->{organisation}->{street_name}, - town => $_->{organisation}->{town}, - postcode => $_->{organisation}->{postcode}, + # Extra custom error, because its funny + if ( $json->{north_east}->{latitude} < $json->{south_west}->{latitude} ) { + return $c->render( + json => { + success => Mojo::JSON->false, + errors => ['upside_down'], + }, + status => 400, + ); } - } $org_rs->all ]; - - $c->render( - json => { - success => Mojo::JSON->true, - locations => $locations, - self => { - latitude => $entity_type_object->latitude, - longitude => $entity_type_object->longitude, - } - }, - ); + + my $entity = $c->stash->{api_user}->entity; + my $entity_type_object = $entity->type_object; + my $orgs_lis = $c->schema->resultset('EntityAssociation')->search( + { + $json->{association} => 1, + }, + ); + + # need: organisations only, with name, latitude, and longitude + my $org_rs = $orgs_lis->search_related( + 'entity', + { + 'entity.type' => 'organisation', + 'organisation.latitude' => { + -between => [ + $json->{south_west}->{latitude}, + $json->{north_east}->{latitude}, + ] + }, + 'organisation.longitude' => { + -between => [ + $json->{south_west}->{longitude}, + $json->{north_east}->{longitude}, + ] + }, + }, + { + join => [qw/ organisation /], + columns => [ + 'organisation.name', 'organisation.latitude', + 'organisation.longitude', 'organisation.street_name', + 'organisation.town', 'organisation.postcode', + ], + group_by => [qw/ organisation.id /], + }, + ); + + $org_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); + + my $locations = [ + map { + { + latitude => $_->{organisation}->{latitude} * 1, + longitude => $_->{organisation}->{longitude} * 1, + name => $_->{organisation}->{name}, + street_name => $_->{organisation}->{street_name}, + town => $_->{organisation}->{town}, + postcode => $_->{organisation}->{postcode}, + } + } $org_rs->all + ]; + + $c->render( + json => { + success => Mojo::JSON->true, + locations => $locations, + self => { + latitude => $entity_type_object->latitude, + longitude => $entity_type_object->longitude, + } + }, + ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/User/Medals.pm b/lib/Pear/LocalLoop/Controller/Api/V1/User/Medals.pm index 2664935..8a10846 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/User/Medals.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/User/Medals.pm @@ -3,46 +3,46 @@ use Mojo::Base 'Mojolicious::Controller'; use Mojo::JSON qw/true false/; sub index { - my $c = shift; + my $c = shift; - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); - # Placeholder data - my $global_placeholder = { - group_name => { - threshold => { - awarded => true, - awarded_at => '2017-01-02T01:00:00Z', - threshold => 1, - points => 1, - }, - total => 1, - }, - }; - my $organisation_placeholder = { - org_id => { - group_name => { - threshold => { - awarded => true, - awarded_at => '2017-01-02T01:00:00Z', - threshold => 1, - points => 1, - multiplier => 1, + # Placeholder data + my $global_placeholder = { + group_name => { + threshold => { + awarded => true, + awarded_at => '2017-01-02T01:00:00Z', + threshold => 1, + points => 1, + }, + total => 1, }, - total => 1, - }, - name => 'Placeholder', - }, - }; + }; + my $organisation_placeholder = { + org_id => { + group_name => { + threshold => { + awarded => true, + awarded_at => '2017-01-02T01:00:00Z', + threshold => 1, + points => 1, + multiplier => 1, + }, + total => 1, + }, + name => 'Placeholder', + }, + }; - return $c->render( - json => { - success => Mojo::JSON->true, - global => $global_placeholder, - organisation => $organisation_placeholder, - } - ); + return $c->render( + json => { + success => Mojo::JSON->true, + global => $global_placeholder, + organisation => $organisation_placeholder, + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/User/Points.pm b/lib/Pear/LocalLoop/Controller/Api/V1/User/Points.pm index 5dc7a25..688cd90 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/User/Points.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/User/Points.pm @@ -3,37 +3,37 @@ use Mojo::Base 'Mojolicious::Controller'; use Mojo::JSON qw/true false/; sub index { - my $c = shift; + my $c = shift; - my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); - # Placeholder data - my $snippets_placeholder = { - points_total => 1, - point_last => 1, - trans_count => 1, - avg_multi => 1, - }; + # Placeholder data + my $snippets_placeholder = { + points_total => 1, + point_last => 1, + trans_count => 1, + avg_multi => 1, + }; - my $widget_line_placeholder = { labels => [], data => [] }; + my $widget_line_placeholder = { labels => [], data => [] }; - my $widget_progress_placeholder = { - this_week => 1, - last_week => 1, - max => 1, - sum => 1, - count => 1, - }; + my $widget_progress_placeholder = { + this_week => 1, + last_week => 1, + max => 1, + sum => 1, + count => 1, + }; - return $c->render( - json => { - success => Mojo::JSON->true, - snippets => $snippets_placeholder, - widget_line => $widget_line_placeholder, - widget_progress => $widget_progress_placeholder, - } - ); + return $c->render( + json => { + success => Mojo::JSON->true, + snippets => $snippets_placeholder, + widget_line => $widget_line_placeholder, + widget_progress => $widget_progress_placeholder, + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Controller/Portal.pm b/lib/Pear/LocalLoop/Controller/Portal.pm index 5e4b4ef..eb3f8a3 100644 --- a/lib/Pear/LocalLoop/Controller/Portal.pm +++ b/lib/Pear/LocalLoop/Controller/Portal.pm @@ -2,10 +2,10 @@ package Pear::LocalLoop::Controller::Portal; use Mojo::Base 'Mojolicious::Controller'; sub under { - my $c = shift; + my $c = shift; - $c->stash( api_user => $c->current_user ); - return 1; + $c->stash( api_user => $c->current_user ); + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Root.pm b/lib/Pear/LocalLoop/Controller/Root.pm index c2dddba..28a089e 100644 --- a/lib/Pear/LocalLoop/Controller/Root.pm +++ b/lib/Pear/LocalLoop/Controller/Root.pm @@ -2,42 +2,43 @@ package Pear::LocalLoop::Controller::Root; use Mojo::Base 'Mojolicious::Controller'; sub index { - my $c = shift; + my $c = shift; -# if ( $c->is_user_authenticated ) { -# $c->redirect_to('/home'); -# } + # if ( $c->is_user_authenticated ) { + # $c->redirect_to('/home'); + # } } sub under { - my $c = shift; + my $c = shift; - if ( $c->is_user_authenticated ) { - return 1; - } - $c->redirect_to('/'); - return; + if ( $c->is_user_authenticated ) { + return 1; + } + $c->redirect_to('/'); + return; } sub auth_login { - my $c = shift; - - if ( $c->authenticate($c->param('email'), $c->param('password')) ) { - $c->redirect_to('/home'); - } else { - $c->redirect_to('/'); - } + my $c = shift; + + if ( $c->authenticate( $c->param('email'), $c->param('password') ) ) { + $c->redirect_to('/home'); + } + else { + $c->redirect_to('/'); + } } sub auth_logout { - my $c = shift; + my $c = shift; - $c->logout; - $c->redirect_to('/'); + $c->logout; + $c->redirect_to('/'); } sub home { - my $c = shift; + my $c = shift; } 1; diff --git a/lib/Pear/LocalLoop/Error.pm b/lib/Pear/LocalLoop/Error.pm index be700d0..bef31c3 100644 --- a/lib/Pear/LocalLoop/Error.pm +++ b/lib/Pear/LocalLoop/Error.pm @@ -1,10 +1,7 @@ package Pear::LocalLoop::Error; -use Moo; -extends 'Throwable::Error'; -package Pear::LocalLoop::ImplementationError; use Moo; -use namespace::clean; -extends 'Pear::LocalLoop::Error'; + +extends 'Throwable::Error'; 1; diff --git a/lib/Pear/LocalLoop/ImplementationError.pm b/lib/Pear/LocalLoop/ImplementationError.pm new file mode 100644 index 0000000..9b5d5c6 --- /dev/null +++ b/lib/Pear/LocalLoop/ImplementationError.pm @@ -0,0 +1,8 @@ +package Pear::LocalLoop::ImplementationError; + +use Moo; +use namespace::clean; + +extends 'Pear::LocalLoop::Error'; + +1; diff --git a/lib/Pear/LocalLoop/Import/LCCCsv.pm b/lib/Pear/LocalLoop/Import/LCCCsv.pm index 34be817..febc13b 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv.pm @@ -3,21 +3,22 @@ use Moo; use Pear::LocalLoop::Error; has external_name => ( - is => 'ro', - default => 'LCC CSV', + is => 'ro', + default => 'LCC CSV', ); has csv_required_columns => ( - is => 'lazy', - builder => sub { - Pear::LocalLoop::ImplementationError->throw("Must be implemented by child class"); - }, + is => 'lazy', + builder => sub { + Pear::LocalLoop::ImplementationError->throw( + "Must be implemented by child class"); + }, ); with qw/ Pear::LocalLoop::Import::Role::ExternalName Pear::LocalLoop::Import::Role::Schema Pear::LocalLoop::Import::Role::CSV -/; + /; 1; diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm index fc01288..164e484 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm @@ -6,38 +6,45 @@ use Geo::UK::Postcode::Regex; extends qw/Pear::LocalLoop::Import::LCCCsv/; has '+csv_required_columns' => ( - builder => sub { return [ qw/ - postcode - ward - / ]}, + builder => sub { + return [ + qw/ + postcode + ward + / + ]; + }, ); sub import_csv { - my ($self) = @_; + my ($self) = @_; - $self->check_headers; + $self->check_headers; - while ( my $row = $self->get_csv_line ) { - $self->_row_to_result($row); - } + while ( my $row = $self->get_csv_line ) { + $self->_row_to_result($row); + } } sub _row_to_result { - my ( $self, $row ) = @_; + my ( $self, $row ) = @_; - my $postcode_obj = Geo::UK::Postcode::Regex->parse( $row->{postcode} ); + my $postcode_obj = Geo::UK::Postcode::Regex->parse( $row->{postcode} ); - my $ward = $self->schema->resultset('GbWard')->find_or_create(ward => $row->{ward}); + my $ward = $self->schema->resultset('GbWard') + ->find_or_create( ward => $row->{ward} ); - my $postcode_r = $self->schema->resultset('GbPostcode')->find({ - outcode => $postcode_obj->{outcode}, - incode => $postcode_obj->{incode}, - }); + my $postcode_r = $self->schema->resultset('GbPostcode')->find( + { + outcode => $postcode_obj->{outcode}, + incode => $postcode_obj->{incode}, + } + ); - return unless $postcode_r; - return if $postcode_r->ward; + return unless $postcode_r; + return if $postcode_r->ward; - $postcode_r->update({ ward_id => $ward->id }); + $postcode_r->update( { ward_id => $ward->id } ); } 1; diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm index c191534..5ba709a 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm @@ -4,45 +4,58 @@ use Moo; extends qw/Pear::LocalLoop::Import::LCCCsv/; has '+csv_required_columns' => ( - builder => sub { return [ qw/ - supplier_id - name - / ]}, + builder => sub { + return [ + qw/ + supplier_id + name + / + ]; + }, ); sub import_csv { - my ($self) = @_; + my ($self) = @_; - $self->check_headers; + $self->check_headers; - while ( my $row = $self->get_csv_line ) { - $self->_row_to_result($row); - } + while ( my $row = $self->get_csv_line ) { + $self->_row_to_result($row); + } } sub _row_to_result { - my ( $self, $row ) = @_; - - my $addr2 = $row->{post_town}; - - my $address = ( defined $addr2 ? ( $row->{"address line 2"} . ' ' . $addr2) : $row->{"address line 2"} ); - - return if $self->external_result->organisations->find({external_id => $row->{supplier_id}}); - - $self->schema->resultset('Entity')->create({ - type => 'organisation', - organisation => { - name => $row->{name}, - street_name => $row->{"address line 1"}, - town => $address, - postcode => $row->{post_code}, - country => $row->{country_code}, - external_reference => [ { - external_reference => $self->external_result, - external_id => $row->{supplier_id}, - } ], - } - }); + my ( $self, $row ) = @_; + + my $addr2 = $row->{post_town}; + + my $address = ( + defined $addr2 + ? ( $row->{"address line 2"} . ' ' . $addr2 ) + : $row->{"address line 2"} ); + + return + if $self->external_result->organisations->find( + { external_id => $row->{supplier_id} } ); + + $self->schema->resultset('Entity')->create( + { + type => 'organisation', + organisation => { + name => $row->{name}, + street_name => $row->{"address line 1"}, + town => $address, + postcode => $row->{post_code}, + country => $row->{country_code}, + external_reference => [ + { + external_reference => $self->external_result, + external_id => $row->{supplier_id}, + } + ], + } + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm index 5af13fe..1dfbeb4 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm @@ -8,121 +8,179 @@ use Geo::UK::Postcode::Regex; extends qw/Pear::LocalLoop::Import::LCCCsv/; has target_entity_id => ( - is => 'ro', - required => 1, + is => 'ro', + required => 1, ); has target_entity => ( - is => 'lazy', - builder => sub { - my $self = shift; - my $entity = $self->schema->resultset('Entity')->find($self->target_entity_id); - Pear::LocalLoop::Error->throw("Cannot find LCC Entity, did you pass the right id?") unless $entity; - return $entity; - }, + is => 'lazy', + builder => sub { + my $self = shift; + my $entity = + $self->schema->resultset('Entity')->find( $self->target_entity_id ); + Pear::LocalLoop::Error->throw( + "Cannot find LCC Entity, did you pass the right id?") + unless $entity; + return $entity; + }, ); has '+csv_required_columns' => ( - builder => sub {return [ ( - 'transaction_id', - 'supplier_id', - 'net_amount', - 'vat amount', - 'gross_amount', - ) ]}, + builder => sub { + return [ + ( + 'transaction_id', 'supplier_id', + 'net_amount', 'vat amount', + 'gross_amount', + ) + ]; + }, ); sub import_csv { - my ($self) = @_; + my ($self) = @_; - $self->check_headers; - my $lcc_org = $self->target_entity; + $self->check_headers; + my $lcc_org = $self->target_entity; - while ( my $row = $self->get_csv_line ) { - $self->_row_to_result($row, $lcc_org); - } + while ( my $row = $self->get_csv_line ) { + $self->_row_to_result( $row, $lcc_org ); + } } sub _row_to_result { - my ($self, $row, $lcc_org) = @_; - - my $supplier_id = $row->{supplier_id}; - - my $organisation = $self->schema->resultset('Organisation')->find({ - 'external_reference.external_id' => $supplier_id - }, { join => 'external_reference' }); - - unless ($organisation) { - # Pear::LocalLoop::Error->throw("Cannot find an organisation with supplier_id $supplier_id"); - - return unless $row->{'Company Name (WHO)'}; - - my $town = $row->{post_town}; - - unless ($town) { - my $postcode_obj = Geo::UK::Postcode::Regex->parse( $row->{post_code} ); - $town = Geo::UK::Postcode::Regex->outcode_to_posttowns($postcode_obj->{outcode}); - $town = $town->[0]; + my ( $self, $row, $lcc_org ) = @_; + + my $supplier_id = $row->{supplier_id}; + + my $organisation = $self->schema->resultset('Organisation')->find( + { + 'external_reference.external_id' => $supplier_id + }, + { join => 'external_reference' } + ); + + unless ($organisation) { + +# Pear::LocalLoop::Error->throw("Cannot find an organisation with supplier_id $supplier_id"); + + return unless $row->{'Company Name (WHO)'}; + + my $town = $row->{post_town}; + + unless ($town) { + my $postcode_obj = + Geo::UK::Postcode::Regex->parse( $row->{post_code} ); + $town = Geo::UK::Postcode::Regex->outcode_to_posttowns( + $postcode_obj->{outcode} ); + $town = $town->[0]; + } + + return + if $self->external_result->organisations->find( + { external_id => $row->{supplier_id} } ); + + $organisation = $self->schema->resultset('Entity')->create( + { + type => 'organisation', + organisation => { + name => $row->{'Company Name (WHO)'}, + street_name => $row->{"address line 1"}, + town => $town, + postcode => $row->{post_code}, + country => $row->{country_code}, + external_reference => [ + { + external_reference => $self->external_result, + external_id => $row->{supplier_id}, + } + ], + } + } + ); } - return if $self->external_result->organisations->find({external_id => $row->{supplier_id}}); - - $organisation = $self->schema->resultset('Entity')->create({ - type => 'organisation', - organisation => { - name => $row->{'Company Name (WHO)'}, - street_name => $row->{"address line 1"}, - town => $town, - postcode => $row->{post_code}, - country => $row->{country_code}, - external_reference => [ { - external_reference => $self->external_result, - external_id => $row->{supplier_id}, - } ], - } - }); - } - - my $date_formatter = DateTime::Format::Strptime->new( - pattern => '%m/%d/%Y', - time_zone => 'Europe/London' - ); - - my $paid_date = ( $row->{paid_date} ? - $date_formatter->parse_datetime($row->{paid_date}) : - $date_formatter->parse_datetime($row->{invoice_date}) ); - - my $gross_value = $row->{gross_amount}; - $gross_value =~ s/,//g; - my $sales_tax_value = $row->{"vat amount"}; - $sales_tax_value =~ s/,//g; - my $net_value = $row->{net_amount}; - $net_value =~ s/,//g; - - # TODO negative values are sometimes present - my $external_transaction = $self->external_result->update_or_create_related('transactions', { # This is a TransactionExternal result - external_id => $row->{transaction_id}, - }); - - my $transaction_result = $external_transaction->update_or_create_related( 'transaction', { - seller => $organisation->entity, - buyer => $lcc_org, - purchase_time => $paid_date, - value => $gross_value * 100000, - }); - - my $meta_result = $transaction_result->update_or_create_related('meta', { - gross_value => $gross_value * 100000, - sales_tax_value => $sales_tax_value * 100000, - net_value => $net_value * 100000, - ($row->{"local service"} ? (local_service => $row->{"local service"}) : ()), - ($row->{"regional service"} ? (regional_service => $row->{"regional service"}) : ()), - ($row->{"national service"} ? (national_service => $row->{"national service"}) : ()), - ($row->{"private household rebate"} ? (private_household_rebate => $row->{"private household rebate"}) : ()), - ($row->{"business tax and rebate"} ? (business_tax_and_rebate => $row->{"business tax and rebate"}) : ()), - ($row->{"stat loc gov"} ? (stat_loc_gov => $row->{"stat loc gov"}) : ()), - ($row->{"central loc gov"} ? (central_loc_gov => $row->{"central loc gov"}) : ()), - }); + my $date_formatter = DateTime::Format::Strptime->new( + pattern => '%m/%d/%Y', + time_zone => 'Europe/London' + ); + + my $paid_date = ( + $row->{paid_date} + ? $date_formatter->parse_datetime( $row->{paid_date} ) + : $date_formatter->parse_datetime( $row->{invoice_date} ) + ); + + my $gross_value = $row->{gross_amount}; + $gross_value =~ s/,//g; + my $sales_tax_value = $row->{"vat amount"}; + $sales_tax_value =~ s/,//g; + my $net_value = $row->{net_amount}; + $net_value =~ s/,//g; + + # TODO negative values are sometimes present + my $external_transaction = $self->external_result->update_or_create_related( + 'transactions', + { # This is a TransactionExternal result + external_id => $row->{transaction_id}, + } + ); + + my $transaction_result = $external_transaction->update_or_create_related( + 'transaction', + { + seller => $organisation->entity, + buyer => $lcc_org, + purchase_time => $paid_date, + value => $gross_value * 100000, + } + ); + + my $meta_result = $transaction_result->update_or_create_related( + 'meta', + { + gross_value => $gross_value * 100000, + sales_tax_value => $sales_tax_value * 100000, + net_value => $net_value * 100000, + ( + $row->{"local service"} + ? ( local_service => $row->{"local service"} ) + : () + ), + ( + $row->{"regional service"} + ? ( regional_service => $row->{"regional service"} ) + : () + ), + ( + $row->{"national service"} + ? ( national_service => $row->{"national service"} ) + : () + ), + ( + $row->{"private household rebate"} + ? ( private_household_rebate => + $row->{"private household rebate"} ) + : () + ), + ( + $row->{"business tax and rebate"} + ? ( business_tax_and_rebate => + $row->{"business tax and rebate"} ) + : () + ), + ( + $row->{"stat loc gov"} + ? ( stat_loc_gov => $row->{"stat loc gov"} ) + : () + ), + ( + $row->{"central loc gov"} + ? ( central_loc_gov => $row->{"central loc gov"} ) + : () + ), + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Import/Role/CSV.pm b/lib/Pear/LocalLoop/Import/Role/CSV.pm index 954d986..b2800e8 100644 --- a/lib/Pear/LocalLoop/Import/Role/CSV.pm +++ b/lib/Pear/LocalLoop/Import/Role/CSV.pm @@ -9,80 +9,82 @@ use Pear::LocalLoop::Error; requires 'csv_required_columns'; has csv_file => ( - is => 'ro', - predicate => 1, + is => 'ro', + predicate => 1, ); has csv_string => ( - is => 'ro', - predicate => 1, + is => 'ro', + predicate => 1, ); has csv_error => ( - is => 'ro', - predicate => 1, + is => 'ro', + predicate => 1, ); has _csv_filehandle => ( - is => 'lazy', - builder => sub { - my $self = shift; - my $fh; - if ( $self->has_csv_file ) { - open $fh, '<', $self->csv_file; - } elsif ( $self->has_csv_string ) { - my $string = $self->csv_string; - open $fh, '<', \$string; - } else { - die "Must provide csv_file or csv_string" + is => 'lazy', + builder => sub { + my $self = shift; + my $fh; + if ( $self->has_csv_file ) { + open $fh, '<', $self->csv_file; + } + elsif ( $self->has_csv_string ) { + my $string = $self->csv_string; + open $fh, '<', \$string; + } + else { + die "Must provide csv_file or csv_string"; + } + return $fh; } - return $fh; - } ); has text_csv_options => ( - is => 'lazy', - builder => sub { - return { - binary => 1, - allow_whitespace => 1, - }; - } + is => 'lazy', + builder => sub { + return { + binary => 1, + allow_whitespace => 1, + }; + } ); has _text_csv => ( - is => 'lazy', - builder => sub { - return Text::CSV->new(shift->text_csv_options); - } + is => 'lazy', + builder => sub { + return Text::CSV->new( shift->text_csv_options ); + } ); has csv_data => ( - is => 'lazy', - builder => sub { - my $self = shift; - my $header_check = $self->check_headers; - return 0 unless $header_check; - return $self->_text_csv->getline_hr_all( $self->_csv_filehandle ); - } + is => 'lazy', + builder => sub { + my $self = shift; + my $header_check = $self->check_headers; + return 0 unless $header_check; + return $self->_text_csv->getline_hr_all( $self->_csv_filehandle ); + } ); sub get_csv_line { - my $self = shift; - return $self->_text_csv->getline_hr( $self->_csv_filehandle ); + my $self = shift; + return $self->_text_csv->getline_hr( $self->_csv_filehandle ); } sub check_headers { - my $self = shift; - my $req_headers = $self->csv_required_columns; - my @headers; - @headers = $self->_text_csv->header( $self->_csv_filehandle ); - my %header_map = ( map { $_ => 1 } @headers ); - for my $req_header ( @$req_headers ) { - next if $header_map{$req_header}; - die "Require header [" . $req_header . "]"; - } - return 1; + my $self = shift; + my $req_headers = $self->csv_required_columns; + my @headers; + @headers = $self->_text_csv->header( $self->_csv_filehandle ); + my %header_map = ( map { $_ => 1 } @headers ); + for my $req_header (@$req_headers) { + next if $header_map{$req_header}; + die "Require header [" . $req_header . "]"; + } + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Import/Role/ExternalName.pm b/lib/Pear/LocalLoop/Import/Role/ExternalName.pm index 40c06fa..244c1db 100644 --- a/lib/Pear/LocalLoop/Import/Role/ExternalName.pm +++ b/lib/Pear/LocalLoop/Import/Role/ExternalName.pm @@ -6,14 +6,15 @@ use Moo::Role; requires qw/ external_name schema -/; + /; has external_result => ( - is => 'lazy', - builder => sub { - my $self = shift; - return $self->schema->resultset('ExternalReference')->find_or_create({ name => $self->external_name }); - } + is => 'lazy', + builder => sub { + my $self = shift; + return $self->schema->resultset('ExternalReference') + ->find_or_create( { name => $self->external_name } ); + } ); 1; diff --git a/lib/Pear/LocalLoop/Import/Role/Schema.pm b/lib/Pear/LocalLoop/Import/Role/Schema.pm index 71bae0c..c97a5d2 100644 --- a/lib/Pear/LocalLoop/Import/Role/Schema.pm +++ b/lib/Pear/LocalLoop/Import/Role/Schema.pm @@ -4,8 +4,8 @@ use warnings; use Moo::Role; has schema => ( - is => 'ro', - required => 1, + is => 'ro', + required => 1, ); -1; \ No newline at end of file +1; diff --git a/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm b/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm index 6f94a03..5ee6fec 100644 --- a/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm +++ b/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm @@ -1,8 +1,9 @@ package Pear::LocalLoop::Plugin::BootstrapPagination; -# nabbed from Mojolicious::Plugin::BootstrapPagination - + +# nabbed from Mojolicious::Plugin::BootstrapPagination - # https://github.com/csroli/Mojolicious-Plugin-BootstrapPagination use Mojo::Base 'Mojolicious::Plugin'; -use POSIX( qw/ceil/ ); +use POSIX(qw/ceil/); use Mojo::ByteStream 'b'; use strict; @@ -11,85 +12,170 @@ use warnings; our $VERSION = "0.14"; # Homer: Well basically, I just copied the plant we have now. -# Then, I added some fins to lower wind resistance. +# Then, I added some fins to lower wind resistance. # And this racing stripe here I feel is pretty sharp. # Burns: Agreed. First prize! -sub register{ - my ( $self, $app, $args ) = @_; - $args ||= {}; - - $app->helper( bootstrap_pagination => sub{ - my ( $self, $actual, $count, $opts ) = @_; - my %bs4classes = (list_class => "page-item", anchor_class => "page-link"); - - my $localize = ( $opts->{localize} || $args->{localize} ) ? - ( $opts->{localize} || $args->{localize} ) : undef; - - $count = ceil($count); - return "" unless $count > 1; - $opts = {} unless $opts; - my $round = $opts->{round} || $args->{round} || 4; - my $param = $opts->{param} || $args->{param} || "page"; - my $class = $opts->{class} || $args->{class} || ""; - my $bs4 = $opts->{bootstrap4} || $args->{bootstrap4} || undef; - - if ($class ne ""){ - $class = " " . $class; - } - my $outer = $opts->{outer} || $args->{outer} || 2; - my $query = exists $opts->{query} ? $opts->{query} : $args->{query} || ""; - my $start = $opts->{start} // $args->{start} // 1; - my @current = ( $actual - $round .. $actual + $round ); - my @first = ($start.. $start + $outer - 1); - my @tail = ( $count - $outer + 1 .. $count ); - my @ret = (); - my $last = undef; - foreach my $number( sort { $a <=> $b } @current, @first, @tail ){ - next if ( $last && $last == $number && $start > 0 ) || ( defined $last && $last == $number && $start == 0 ); - next if ( $number <= 0 && $start > 0) || ( $number < 0 && $start == 0 ); - last if ( $number > $count && $start > 0 ) || ( $number >= $count && $start == 0 ); - push @ret, ".." if( $last && $last + 1 != $number ); - push @ret, $number; - $last = $number; - } - my $html = "
    "; - if( $actual == $start ){ - $html .= "
  • «
  • "; - } else { - $html .= "url_with->query( [$param => $actual - 1] ) . $query . "\" >«"; - } - my $last_num = -1; - foreach my $number( @ret ){ - my $show_number = $start > 0 ? $number : ( $number =~ /\d+/ ? $number + 1 : $number ); - - if ( $localize ) { - $show_number = $localize->($self, $show_number); - } - - if( $number eq ".." && $last_num < $actual ){ - my $offset = ceil( ( $actual - $round ) / 2 ) + 1 ; - $html .= "url_with->query( [$param => $start == 0 ? $offset + 1 : $offset] ) . $query ."\" >…"; +sub register { + my ( $self, $app, $args ) = @_; + $args ||= {}; + + $app->helper( + bootstrap_pagination => sub { + my ( $self, $actual, $count, $opts ) = @_; + my %bs4classes = + ( list_class => "page-item", anchor_class => "page-link" ); + + my $localize = + ( $opts->{localize} || $args->{localize} ) + ? ( $opts->{localize} || $args->{localize} ) + : undef; + + $count = ceil($count); + return "" unless $count > 1; + $opts = {} unless $opts; + my $round = $opts->{round} || $args->{round} || 4; + my $param = $opts->{param} || $args->{param} || "page"; + my $class = $opts->{class} || $args->{class} || ""; + my $bs4 = $opts->{bootstrap4} || $args->{bootstrap4} || undef; + + if ( $class ne "" ) { + $class = " " . $class; + } + my $outer = $opts->{outer} || $args->{outer} || 2; + my $query = + exists $opts->{query} ? $opts->{query} : $args->{query} || ""; + my $start = $opts->{start} // $args->{start} // 1; + my @current = ( $actual - $round .. $actual + $round ); + my @first = ( $start .. $start + $outer - 1 ); + my @tail = ( $count - $outer + 1 .. $count ); + my @ret = (); + my $last = undef; + + foreach my $number ( sort { $a <=> $b } @current, @first, @tail ) { + next + if ( $last && $last == $number && $start > 0 ) + || ( defined $last && $last == $number && $start == 0 ); + next + if ( $number <= 0 && $start > 0 ) + || ( $number < 0 && $start == 0 ); + last + if ( $number > $count && $start > 0 ) + || ( $number >= $count && $start == 0 ); + push @ret, ".." if ( $last && $last + 1 != $number ); + push @ret, $number; + $last = $number; + } + my $html = "
      "; + if ( $actual == $start ) { + $html .= + "
    • «
    • "; + } + else { + $html .= "url_with->query( [ $param => $actual - 1 ] ) + . $query + . "\" >«"; + } + my $last_num = -1; + foreach my $number (@ret) { + my $show_number = + $start > 0 + ? $number + : ( $number =~ /\d+/ ? $number + 1 : $number ); + + if ($localize) { + $show_number = $localize->( $self, $show_number ); + } + + if ( $number eq ".." && $last_num < $actual ) { + my $offset = ceil( ( $actual - $round ) / 2 ) + 1; + $html .= "url_with->query( + [ $param => $start == 0 ? $offset + 1 : $offset ] ) + . $query + . "\" >…"; + } + elsif ( $number eq ".." && $last_num > $actual ) { + my $back = $count - $outer + 1; + my $forw = $round + $actual; + my $offset = ceil( ( ( $back - $forw ) / 2 ) + $forw ); + $html .= "url_with->query( + [ $param => $start == 0 ? $offset + 1 : $offset ] ) + . $query + . "\" >…"; + } + elsif ( $number == $actual ) { + $html .= + "
    • $show_number
    • "; + } + else { + $html .= "url_with->query( [ $param => $number ] ) + . $query + . "\">$show_number"; + } + $last_num = $number; + } + if ( $actual == $count ) { + $html .= + "
    • url_with->query( [ $param => $actual + 1 ] ) + . $query + . "\" >»
    • "; + } + else { + $html .= "url_with->query( [ $param => $actual + 1 ] ) + . $query + . "\" >»"; + } + $html .= "
    "; + return b($html); } - elsif( $number eq ".." && $last_num > $actual ) { - my $back = $count - $outer + 1; - my $forw = $round + $actual; - my $offset = ceil( ( ( $back - $forw ) / 2 ) + $forw ); - $html .= "url_with->query( [$param => $start == 0 ? $offset + 1 : $offset] ) . $query ."\" >…"; - } elsif( $number == $actual ) { - $html .= "
  • $show_number
  • "; - } else { - $html .= "url_with->query( [$param => $number] ) . $query ."\">$show_number"; - } - $last_num = $number; - } - if( $actual == $count ){ - $html .= "
  • url_with->query( [$param => $actual + 1] ) . $query . "\" >»
  • "; - } else { - $html .= "url_with->query( [$param => $actual + 1] ) . $query . "\" >»"; - } - $html .= "
"; - return b( $html ); - } ); + ); } diff --git a/lib/Pear/LocalLoop/Plugin/Currency.pm b/lib/Pear/LocalLoop/Plugin/Currency.pm index fa5333f..68cec27 100644 --- a/lib/Pear/LocalLoop/Plugin/Currency.pm +++ b/lib/Pear/LocalLoop/Plugin/Currency.pm @@ -2,23 +2,28 @@ package Pear::LocalLoop::Plugin::Currency; use Mojo::Base 'Mojolicious::Plugin'; sub register { - my ( $plugin, $app, $cong ) = @_; + my ( $plugin, $app, $cong ) = @_; - $app->helper( parse_currency => sub { - my ( $c, $currency_string ) = @_; - my $value; - if ( $currency_string =~ /^£([\d.]+)/ ) { - $value = $1 * 1; - } elsif ( $currency_string =~ /^([\d.]+)/ ) { - $value = $1 * 1; - } - return $value; - }); + $app->helper( + parse_currency => sub { + my ( $c, $currency_string ) = @_; + my $value; + if ( $currency_string =~ /^£([\d.]+)/ ) { + $value = $1 * 1; + } + elsif ( $currency_string =~ /^([\d.]+)/ ) { + $value = $1 * 1; + } + return $value; + } + ); - $app->helper( format_currency_from_db => sub { - my ( $c, $value ) = @_; - return sprintf( '£%.2f', $value / 100000 ); - }); + $app->helper( + format_currency_from_db => sub { + my ( $c, $value ) = @_; + return sprintf( '£%.2f', $value / 100000 ); + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Datetime.pm b/lib/Pear/LocalLoop/Plugin/Datetime.pm index c6f2e55..c942656 100644 --- a/lib/Pear/LocalLoop/Plugin/Datetime.pm +++ b/lib/Pear/LocalLoop/Plugin/Datetime.pm @@ -4,85 +4,96 @@ use Mojo::Base 'Mojolicious::Plugin'; use DateTime::Format::Strptime; sub register { - my ( $plugin, $app, $conf ) = @_; + my ( $plugin, $app, $conf ) = @_; - $app->helper( human_datetime_parser => sub { - return DateTime::Format::Strptime->new( pattern => '%x %X' ); - }); + $app->helper( + human_datetime_parser => sub { + return DateTime::Format::Strptime->new( pattern => '%x %X' ); + } + ); - $app->helper( format_human_datetime => sub { - my ( $c, $datetime_obj ) = @_; - return $c->human_datetime_parser->format_datetime( - $datetime_obj, + $app->helper( + format_human_datetime => sub { + my ( $c, $datetime_obj ) = @_; + return $c->human_datetime_parser->format_datetime( $datetime_obj, ); + } ); - }); - $app->helper( iso_datetime_parser => sub { - return DateTime::Format::Strptime->new( pattern => '%Y-%m-%dT%H:%M:%S.%3N%z' ); - }); + $app->helper( + iso_datetime_parser => sub { + return DateTime::Format::Strptime->new( + pattern => '%Y-%m-%dT%H:%M:%S.%3N%z' ); + } + ); - $app->helper( iso_date_parser => sub { - return DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' ); - }); + $app->helper( + iso_date_parser => sub { + return DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' ); + } + ); - $app->helper( iso_month_parser => sub { - return DateTime::Format::Strptime->new( pattern => '%Y-%m' ); - }); + $app->helper( + iso_month_parser => sub { + return DateTime::Format::Strptime->new( pattern => '%Y-%m' ); + } + ); - $app->helper( parse_iso_date => sub { - my ( $c, $date_string ) = @_; - return $c->iso_date_parser->parse_datetime( - $date_string, + $app->helper( + parse_iso_date => sub { + my ( $c, $date_string ) = @_; + return $c->iso_date_parser->parse_datetime( $date_string, ); + } ); - }); - $app->helper( format_iso_date => sub { - my ( $c, $datetime_obj ) = @_; - return $c->iso_date_parser->format_datetime( - $datetime_obj, + $app->helper( + format_iso_date => sub { + my ( $c, $datetime_obj ) = @_; + return $c->iso_date_parser->format_datetime( $datetime_obj, ); + } ); - }); - $app->helper( parse_iso_month => sub { - my ( $c, $date_string ) = @_; - return $c->iso_month_parser->parse_datetime( - $date_string, + $app->helper( + parse_iso_month => sub { + my ( $c, $date_string ) = @_; + return $c->iso_month_parser->parse_datetime( $date_string, ); + } ); - }); - $app->helper( format_iso_month => sub { - my ( $c, $datetime_obj ) = @_; - return $c->iso_month_parser->format_datetime( - $datetime_obj, + $app->helper( + format_iso_month => sub { + my ( $c, $datetime_obj ) = @_; + return $c->iso_month_parser->format_datetime( $datetime_obj, ); + } ); - }); - $app->helper( parse_iso_datetime => sub { - my ( $c, $date_string ) = @_; - return $c->iso_datetime_parser->parse_datetime( - $date_string, + $app->helper( + parse_iso_datetime => sub { + my ( $c, $date_string ) = @_; + return $c->iso_datetime_parser->parse_datetime( $date_string, ); + } ); - }); - $app->helper( format_iso_datetime => sub { - my ( $c, $datetime_obj ) = @_; - return unless defined $datetime_obj; - return $c->iso_datetime_parser->format_datetime( - $datetime_obj, + $app->helper( + format_iso_datetime => sub { + my ( $c, $datetime_obj ) = @_; + return unless defined $datetime_obj; + return $c->iso_datetime_parser->format_datetime( $datetime_obj, ); + } ); - }); - $app->helper( db_datetime_parser => sub { - return shift->schema->storage->datetime_parser; - }); + $app->helper( + db_datetime_parser => sub { + return shift->schema->storage->datetime_parser; + } + ); - $app->helper( format_db_datetime => sub { - my ( $c, $datetime_obj ) = @_; - $datetime_obj->set_time_zone('UTC'); - return $c->db_datetime_parser->format_datetime( - $datetime_obj, + $app->helper( + format_db_datetime => sub { + my ( $c, $datetime_obj ) = @_; + $datetime_obj->set_time_zone('UTC'); + return $c->db_datetime_parser->format_datetime( $datetime_obj, ); + } ); - }); } diff --git a/lib/Pear/LocalLoop/Plugin/Minion.pm b/lib/Pear/LocalLoop/Plugin/Minion.pm index cfe4442..c093c18 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion.pm @@ -4,36 +4,36 @@ use Mojo::Base 'Mojolicious::Plugin'; use Mojo::Loader qw/ find_modules load_class /; sub register { - my ( $plugin, $app, $cong ) = @_; - - if ( defined $app->config->{minion} ) { - $app->log->debug('Setting up Minion tasks'); - $app->plugin('Minion' => $app->config->{minion} ); - - $app->log->debug('Loaded Minion Job packages:'); - - my $job_namespace = __PACKAGE__ . '::Job'; - my @modules = find_modules $job_namespace; - for my $package ( @modules ) { - my ( $job_name ) = $package =~ /${job_namespace}::(.*)$/; - $app->log->debug( $package ); - if (my $e = load_class $package) { - die ref $e ? "Exception: $e" : "$package not found"; - } - $app->minion->add_task( - $job_name => sub { - my ( $job, @args ) = @_; - my $job_runner = $package->new( - job => $job, - ); - $job_runner->run( @args ); + my ( $plugin, $app, $cong ) = @_; + + if ( defined $app->config->{minion} ) { + $app->log->debug('Setting up Minion tasks'); + $app->plugin( 'Minion' => $app->config->{minion} ); + + $app->log->debug('Loaded Minion Job packages:'); + + my $job_namespace = __PACKAGE__ . '::Job'; + my @modules = find_modules $job_namespace; + for my $package (@modules) { + my ($job_name) = $package =~ /${job_namespace}::(.*)$/; + $app->log->debug($package); + if ( my $e = load_class $package) { + die ref $e ? "Exception: $e" : "$package not found"; + } + $app->minion->add_task( + $job_name => sub { + my ( $job, @args ) = @_; + my $job_runner = $package->new( job => $job, ); + $job_runner->run(@args); + } + ); } - ); + + # $app->minion->enqueue('test' => [ 'test arg 1', 'test_arg 2' ] ); + } + else { + $app->log->debug('No Minion Config'); } - # $app->minion->enqueue('test' => [ 'test arg 1', 'test_arg 2' ] ); - } else { - $app->log->debug('No Minion Config'); - } } diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job.pm index 2006845..aaa38b5 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job.pm @@ -1,12 +1,12 @@ package Pear::LocalLoop::Plugin::Minion::Job; use Mojo::Base -base; -has [ qw/ job / ]; +has [qw/ job /]; has app => sub { shift->job->app }; sub run { - die ( __PACKAGE__ . " must implement run sub" ); + die( __PACKAGE__ . " must implement run sub" ); } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm index 51eda90..5511fa1 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm @@ -4,12 +4,12 @@ use Mojo::Base 'Pear::LocalLoop::Plugin::Minion::Job'; use Pear::LocalLoop::Import::LCCCsv::Postcodes; sub run { - my ( $self, $filename ) = @_; + my ( $self, $filename ) = @_; - my $csv_import = Pear::LocalLoop::Import::LCCCsv::Postcodes->new( - csv_file => $filename, - schema => $self->app->schema - )->import_csv; + my $csv_import = Pear::LocalLoop::Import::LCCCsv::Postcodes->new( + csv_file => $filename, + schema => $self->app->schema + )->import_csv; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm index 7c0b5fc..8617517 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm @@ -4,12 +4,12 @@ use Mojo::Base 'Pear::LocalLoop::Plugin::Minion::Job'; use Pear::LocalLoop::Import::LCCCsv::Suppliers; sub run { - my ( $self, $filename ) = @_; + my ( $self, $filename ) = @_; - my $csv_import = Pear::LocalLoop::Import::LCCCsv::Suppliers->new( - csv_file => $filename, - schema => $self->app->schema - )->import_csv; + my $csv_import = Pear::LocalLoop::Import::LCCCsv::Suppliers->new( + csv_file => $filename, + schema => $self->app->schema + )->import_csv; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm index e77b831..a6b7354 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm @@ -4,13 +4,13 @@ use Mojo::Base 'Pear::LocalLoop::Plugin::Minion::Job'; use Pear::LocalLoop::Import::LCCCsv::Transactions; sub run { - my ($self, $filename, $entity_id) = @_; + my ( $self, $filename, $entity_id ) = @_; - Pear::LocalLoop::Import::LCCCsv::Transactions->new( - csv_file => $filename, - schema => $self->app->schema, - target_entity_id => $entity_id, - )->import_csv; + Pear::LocalLoop::Import::LCCCsv::Transactions->new( + csv_file => $filename, + schema => $self->app->schema, + target_entity_id => $entity_id, + )->import_csv; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm index 0959849..57014d4 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm @@ -2,29 +2,34 @@ package Pear::LocalLoop::Plugin::Minion::Job::entity_postcode_lookup; use Mojo::Base 'Pear::LocalLoop::Plugin::Minion::Job'; sub run { - my ( $self, $entity_id ) = @_; + my ( $self, $entity_id ) = @_; - my $entity_rs = $self->app->schema->resultset('Entity'); - $entity_rs = $entity_rs->search({id => $entity_id }) if $entity_id; + my $entity_rs = $self->app->schema->resultset('Entity'); + $entity_rs = $entity_rs->search( { id => $entity_id } ) if $entity_id; - while ( my $entity = $entity_rs->next ) { - my $obj = $entity->type_object; - next unless $obj; + while ( my $entity = $entity_rs->next ) { + my $obj = $entity->type_object; + next unless $obj; - my $postcode_obj = Geo::UK::Postcode::Regex->parse( $obj->postcode ); + my $postcode_obj = Geo::UK::Postcode::Regex->parse( $obj->postcode ); - unless ( defined $postcode_obj && $postcode_obj->{non_geographical} ) { - my $pc_result = $self->app->schema->resultset('GbPostcode')->find({ - incode => $postcode_obj->{incode}, - outcode => $postcode_obj->{outcode}, - }); - if ( defined $pc_result ) { - $entity->update_or_create_related('postcode', { - gb_postcode => $pc_result, - }); - } + unless ( defined $postcode_obj && $postcode_obj->{non_geographical} ) { + my $pc_result = $self->app->schema->resultset('GbPostcode')->find( + { + incode => $postcode_obj->{incode}, + outcode => $postcode_obj->{outcode}, + } + ); + if ( defined $pc_result ) { + $entity->update_or_create_related( + 'postcode', + { + gb_postcode => $pc_result, + } + ); + } + } } - } } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm index 142df7f..e1bbbfd 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm @@ -2,11 +2,11 @@ package Pear::LocalLoop::Plugin::Minion::Job::leaderboards_recalc; use Mojo::Base 'Pear::LocalLoop::Plugin::Minion::Job'; sub run { - my ( $self, @args ) = @_; + my ( $self, @args ) = @_; - my $leaderboard_rs = $self->app->schema->resultset('Leaderboard'); + my $leaderboard_rs = $self->app->schema->resultset('Leaderboard'); - $leaderboard_rs->recalculate_all; + $leaderboard_rs->recalculate_all; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm index e0cfcf0..a02db92 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm @@ -2,12 +2,12 @@ package Pear::LocalLoop::Plugin::Minion::Job::test; use Mojo::Base 'Pear::LocalLoop::Plugin::Minion::Job'; sub run { - my ( $self, @args ) = @_; + my ( $self, @args ) = @_; - $self->job->app->log->debug( 'Testing Job' ); - for my $arg ( @args ) { - $self->job->app->log->debug( $arg ); - } + $self->job->app->log->debug('Testing Job'); + for my $arg (@args) { + $self->job->app->log->debug($arg); + } } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Postcodes.pm b/lib/Pear/LocalLoop/Plugin/Postcodes.pm index ee7b15a..428648b 100644 --- a/lib/Pear/LocalLoop/Plugin/Postcodes.pm +++ b/lib/Pear/LocalLoop/Plugin/Postcodes.pm @@ -5,54 +5,72 @@ use Geo::UK::Postcode::Regex; use GIS::Distance; sub register { - my ( $plugin, $app, $conf ) = @_; - - $app->helper( get_location_from_postcode => sub { - my ( $c, $postcode, $usertype ) = @_; - my $postcode_obj = Geo::UK::Postcode::Regex->parse( $postcode ); - - my $location; - - unless ( defined $postcode_obj && $postcode_obj->{non_geographical} ) { - my $pc_result = $c->schema->resultset('GbPostcode')->find({ - incode => $postcode_obj->{incode}, - outcode => $postcode_obj->{outcode}, - }); - if ( defined $pc_result ) { - # Force truncation here as SQLite is stupid - $location = { - latitude => ( - $usertype eq 'customer' - ? int($pc_result->latitude * 100 ) / 100 - : $pc_result->latitude - ), - longitude => ( - $usertype eq 'customer' - ? int($pc_result->longitude * 100 ) / 100 - : $pc_result->longitude - ), - }; - } - } - return $location; - }); - - $app->helper( get_distance_from_coords => sub { - my ( $c, $buyer, $seller ) = @_; - - my $gis = GIS::Distance->new(); - - my $buyer_lat = $buyer->latitude; - my $buyer_long = $buyer->longitude; - my $seller_lat = $seller->latitude; - my $seller_long = $seller->longitude; - - if ( $buyer_lat && $buyer_long - && $seller_lat && $seller_long ) { - return int( $gis->distance( $buyer_lat, $buyer_long => $seller_lat, $seller_long )->meters ); - } - return; - }); + my ( $plugin, $app, $conf ) = @_; + + $app->helper( + get_location_from_postcode => sub { + my ( $c, $postcode, $usertype ) = @_; + my $postcode_obj = Geo::UK::Postcode::Regex->parse($postcode); + + my $location; + + unless ( defined $postcode_obj + && $postcode_obj->{non_geographical} ) + { + my $pc_result = $c->schema->resultset('GbPostcode')->find( + { + incode => $postcode_obj->{incode}, + outcode => $postcode_obj->{outcode}, + } + ); + if ( defined $pc_result ) { + + # Force truncation here as SQLite is stupid + $location = { + latitude => ( + $usertype eq 'customer' + ? int( $pc_result->latitude * 100 ) / 100 + : $pc_result->latitude + ), + longitude => ( + $usertype eq 'customer' + ? int( $pc_result->longitude * 100 ) / 100 + : $pc_result->longitude + ), + }; + } + } + return $location; + } + ); + + $app->helper( + get_distance_from_coords => sub { + my ( $c, $buyer, $seller ) = @_; + + my $gis = GIS::Distance->new(); + + my $buyer_lat = $buyer->latitude; + my $buyer_long = $buyer->longitude; + my $seller_lat = $seller->latitude; + my $seller_long = $seller->longitude; + + if ( $buyer_lat + && $buyer_long + && $seller_lat + && $seller_long ) + { + return int( + $gis->distance( + $buyer_lat, + $buyer_long => $seller_lat, + $seller_long + )->meters + ); + } + return; + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm b/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm index 87c04d4..55fac82 100644 --- a/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm +++ b/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm @@ -2,16 +2,19 @@ package Pear::LocalLoop::Plugin::TemplateHelpers; use Mojo::Base 'Mojolicious::Plugin'; sub register { - my ( $plugin, $app, $conf ) = @_; + my ( $plugin, $app, $conf ) = @_; - $app->helper( truncate_text => sub { - my ( $c, $string, $length ) = @_; - if ( length $string < $length ) { - return $string; - } else { - return substr( $string, 0, $length - 3 ) . '...'; - } - }); + $app->helper( + truncate_text => sub { + my ( $c, $string, $length ) = @_; + if ( length $string < $length ) { + return $string; + } + else { + return substr( $string, 0, $length - 3 ) . '...'; + } + } + ); } diff --git a/lib/Pear/LocalLoop/Plugin/Validators.pm b/lib/Pear/LocalLoop/Plugin/Validators.pm index c1fa9f6..207ec46 100644 --- a/lib/Pear/LocalLoop/Plugin/Validators.pm +++ b/lib/Pear/LocalLoop/Plugin/Validators.pm @@ -9,170 +9,195 @@ use DateTime::Format::Strptime; use Try::Tiny; sub register { - my ( $plugin, $app, $conf ) = @_; - - $app->validator->add_check( email => sub { - my ( $validation, $name, $email ) = @_; - return Email::Valid->address( $email ) ? undef : 1; - }); - - $app->validator->add_check( in_resultset => sub { - my ( $validation, $name, $value, $key, $rs ) = @_; - return $rs->search({ $key => $value })->count ? undef : 1; - }); - - $app->validator->add_check( not_in_resultset => sub { - my ( $validation, $name, $value, $key, $rs ) = @_; - return $rs->search({ $key => $value })->count ? 1 : undef; - }); - - $app->validator->add_check( postcode => sub { - my ( $validation, $name, $value ) = @_; - return is_valid_pc( $value ) ? undef : 1; - }); - - $app->validator->add_check( number => sub { - my ( $validation, $name, $value ) = @_; - return looks_like_number( $value ) ? undef : 1; - }); - - $app->validator->add_check( gt_num => sub { - my ( $validation, $name, $value, $check ) = @_; - return $value > $check ? undef : 1; - }); - - $app->validator->add_check( lt_num => sub { - my ( $validation, $name, $value, $check ) = @_; - return $value < $check ? undef : 1; - }); - - $app->validator->add_check( filetype => sub { - my ( $validation, $name, $value, $filetype ) = @_; - my ( undef, undef, $extension ) = fileparse $value->filename, qr/\.[^.]*/; - $extension =~ s/^\.//; - return $app->types->type($extension) eq $filetype ? undef : 1; - }); - - $app->validator->add_check( is_iso_date => sub { - my ( $validation, $name, $value ) = @_; - $value = $app->iso_date_parser->parse_datetime( $value ); - return defined $value ? undef : 1; - }); - - $app->validator->add_check( is_full_iso_datetime => sub { - my ( $validation, $name, $value ) = @_; - $value = $app->parse_iso_datetime( $value ); - return defined $value ? undef : 1; - }); - - $app->validator->add_check( is_object => sub { - my ( $validation, $name, $value ) = @_; - return ref ( $value ) eq 'HASH' ? undef : 1; - }); - - $app->validator->add_check( in_range => sub { - my ( $validation, $name, $value, $low, $high ) = @_; - return $low < $value && $value < $high ? undef : 1; - }); - - $app->helper( validation_error => sub { _validation_error(@_) } ); -} + my ( $plugin, $app, $conf ) = @_; -=head2 validation_error + $app->validator->add_check( + email => sub { + my ( $validation, $name, $email ) = @_; + return Email::Valid->address($email) ? undef : 1; + } + ); -Returns undef if there is no validation error, returns true otherwise - having -set the errors up as required. Renders out the errors as an array, with status -400 + $app->validator->add_check( + in_resultset => sub { + my ( $validation, $name, $value, $key, $rs ) = @_; + return $rs->search( { $key => $value } )->count ? undef : 1; + } + ); -=cut + $app->validator->add_check( + not_in_resultset => sub { + my ( $validation, $name, $value, $key, $rs ) = @_; + return $rs->search( { $key => $value } )->count ? 1 : undef; + } + ); -sub _validation_error { - my ( $c, $sub_name ) = @_; - - my $val_data = $c->validation_data->{ $sub_name }; - return unless defined $val_data; - my $data = $c->stash->{api_json}; - - my @errors = _validate_set( $c, $val_data, $data ); - - if ( scalar @errors ) { - my @sorted_errors = sort @errors; - $c->render( - json => { - success => Mojo::JSON->false, - errors => \@sorted_errors, - }, - status => 400, + $app->validator->add_check( + postcode => sub { + my ( $validation, $name, $value ) = @_; + return is_valid_pc($value) ? undef : 1; + } ); - return \@errors; - } - return; -} + $app->validator->add_check( + number => sub { + my ( $validation, $name, $value ) = @_; + return looks_like_number($value) ? undef : 1; + } + ); -sub _validate_set { - my ( $c, $val_data, $data, $parent_name ) = @_; + $app->validator->add_check( + gt_num => sub { + my ( $validation, $name, $value, $check ) = @_; + return $value > $check ? undef : 1; + } + ); - my @errors; + $app->validator->add_check( + lt_num => sub { + my ( $validation, $name, $value, $check ) = @_; + return $value < $check ? undef : 1; + } + ); - # MUST get a raw validation object - my $validation = $c->app->validator->validation; - $validation->input( $data ); + $app->validator->add_check( + filetype => sub { + my ( $validation, $name, $value, $filetype ) = @_; + my ( undef, undef, $extension ) = fileparse $value->filename, + qr/\.[^.]*/; + $extension =~ s/^\.//; + return $app->types->type($extension) eq $filetype ? undef : 1; + } + ); - for my $val_data_key ( keys %$val_data ) { + $app->validator->add_check( + is_iso_date => sub { + my ( $validation, $name, $value ) = @_; + $value = $app->iso_date_parser->parse_datetime($value); + return defined $value ? undef : 1; + } + ); - $validation->topic( $val_data_key ); + $app->validator->add_check( + is_full_iso_datetime => sub { + my ( $validation, $name, $value ) = @_; + $value = $app->parse_iso_datetime($value); + return defined $value ? undef : 1; + } + ); - my $val_set = $val_data->{$val_data_key}; + $app->validator->add_check( + is_object => sub { + my ( $validation, $name, $value ) = @_; + return ref($value) eq 'HASH' ? undef : 1; + } + ); - my $custom_check_prefix = {}; + $app->validator->add_check( + in_range => sub { + my ( $validation, $name, $value, $low, $high ) = @_; + return $low < $value && $value < $high ? undef : 1; + } + ); - for my $val_error ( @{$val_set->{validation}} ) { - my ( $val_validator ) = keys %$val_error; + $app->helper( validation_error => sub { _validation_error(@_) } ); +} - unless ( - $validation->validator->checks->{$val_validator} - || $val_validator =~ /required|optional/ - ) { - $c->app->log->warn( 'Unknown Validator [' . $val_validator . ']' ); - next; - } +=head2 validation_error - if ( my $custom_prefix = $val_error->{ $val_validator }->{ error_prefix } ) { - $custom_check_prefix->{ $val_validator } = $custom_prefix; - } - my $val_args = $val_error->{ $val_validator }->{ args }; - - $validation->$val_validator( - ( $val_validator =~ /required|optional/ ? $val_data_key : () ), - ( defined $val_args ? @$val_args : () ) - ); +Returns undef if there is no validation error, returns true otherwise - having +set the errors up as required. Renders out the errors as an array, with status +400 + +=cut - # stop bothering checking if failed, validation stops after first failure - last if $validation->has_error( $val_data_key ); +sub _validation_error { + my ( $c, $sub_name ) = @_; + + my $val_data = $c->validation_data->{$sub_name}; + return unless defined $val_data; + my $data = $c->stash->{api_json}; + + my @errors = _validate_set( $c, $val_data, $data ); + + if ( scalar @errors ) { + my @sorted_errors = sort @errors; + $c->render( + json => { + success => Mojo::JSON->false, + errors => \@sorted_errors, + }, + status => 400, + ); + return \@errors; } - if ( $validation->has_error( $val_data_key ) ) { - my ( $check ) = @{ $validation->error( $val_data_key ) }; - my $error_prefix = defined $custom_check_prefix->{ $check } - ? $custom_check_prefix->{ $check } - : $check; - my $error_string = join ('_', - $error_prefix, - ( defined $parent_name ? $parent_name : () ), - $val_data_key, - ); - push @errors, $error_string; - } elsif ( defined $val_set->{ children } ) { - push @errors, _validate_set( - $c, - $val_set->{ children }, - $data->{ $val_data_key }, - $val_data_key ); + return; +} + +sub _validate_set { + my ( $c, $val_data, $data, $parent_name ) = @_; + + my @errors; + + # MUST get a raw validation object + my $validation = $c->app->validator->validation; + $validation->input($data); + + for my $val_data_key ( keys %$val_data ) { + + $validation->topic($val_data_key); + + my $val_set = $val_data->{$val_data_key}; + + my $custom_check_prefix = {}; + + for my $val_error ( @{ $val_set->{validation} } ) { + my ($val_validator) = keys %$val_error; + + unless ( $validation->validator->checks->{$val_validator} + || $val_validator =~ /required|optional/ ) + { + $c->app->log->warn( + 'Unknown Validator [' . $val_validator . ']' ); + next; + } + + if ( my $custom_prefix = + $val_error->{$val_validator}->{error_prefix} ) + { + $custom_check_prefix->{$val_validator} = $custom_prefix; + } + my $val_args = $val_error->{$val_validator}->{args}; + + $validation->$val_validator( + ( $val_validator =~ /required|optional/ ? $val_data_key : () ), + ( defined $val_args ? @$val_args : () ) + ); + + # stop bothering checking if failed, validation stops after first failure + last if $validation->has_error($val_data_key); + } + + if ( $validation->has_error($val_data_key) ) { + my ($check) = @{ $validation->error($val_data_key) }; + my $error_prefix = + defined $custom_check_prefix->{$check} + ? $custom_check_prefix->{$check} + : $check; + my $error_string = join( '_', + $error_prefix, ( defined $parent_name ? $parent_name : () ), + $val_data_key, ); + push @errors, $error_string; + } + elsif ( defined $val_set->{children} ) { + push @errors, + _validate_set( $c, $val_set->{children}, $data->{$val_data_key}, + $val_data_key ); + } } - } - return @errors; + return @errors; } 1; diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index 0637931..7333240 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -1,6 +1,6 @@ -use utf8; package Pear::LocalLoop::Schema; +use utf8; use strict; use warnings; diff --git a/lib/Pear/LocalLoop/Schema/Result/AccountToken.pm b/lib/Pear/LocalLoop/Schema/Result/AccountToken.pm index 51e2f1f..bf673b9 100644 --- a/lib/Pear/LocalLoop/Schema/Result/AccountToken.pm +++ b/lib/Pear/LocalLoop/Schema/Result/AccountToken.pm @@ -8,16 +8,16 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("account_tokens"); __PACKAGE__->add_columns( - "id", - { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, - "name", - { data_type => "text", is_nullable => 0 }, - "used", - { data_type => "integer", default_value => 0, is_nullable => 0 }, + "id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "name", + { data_type => "text", is_nullable => 0 }, + "used", + { data_type => "integer", default_value => 0, is_nullable => 0 }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint(["name"]); +__PACKAGE__->add_unique_constraint( ["name"] ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Category.pm b/lib/Pear/LocalLoop/Schema/Result/Category.pm index 9f27564..789c7a7 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Category.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Category.pm @@ -8,39 +8,37 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("category"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "name" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, - # See here for all possible options http://simplelineicons.com/ - "line_icon" => { - data_type => "varchar", - size => 255, - is_nullable => 1, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + + # See here for all possible options http://simplelineicons.com/ + "line_icon" => { + data_type => "varchar", + size => 255, + is_nullable => 1, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint(["name"]); +__PACKAGE__->add_unique_constraint( ["name"] ); __PACKAGE__->has_many( - "transaction_category", - "Pear::LocalLoop::Schema::Result::TransactionCategory", - { "foreign.category_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 1 }, + "transaction_category", + "Pear::LocalLoop::Schema::Result::TransactionCategory", + { "foreign.category_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 1 }, ); -__PACKAGE__->many_to_many( - "transactions", - "transaction_category", - "transaction", -); +__PACKAGE__->many_to_many( "transactions", "transaction_category", + "transaction", ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Customer.pm b/lib/Pear/LocalLoop/Schema/Result/Customer.pm index 1cc147b..acd6330 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Customer.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Customer.pm @@ -8,55 +8,52 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("customers"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "entity_id" => { - data_type => "integer", - is_nullable => 0, - is_foreign_key => 1, - }, - "display_name" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, - "full_name" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, - "year_of_birth" => { - data_type => "integer", - is_nullable => 0, - }, - "postcode" => { - data_type => "varchar", - size => 16, - is_nullable => 0, - }, - latitude => { - data_type => 'decimal', - size => [5,2], - is_nullable => 1, - default_value => undef, - }, - longitude => { - data_type => 'decimal', - size => [5,2], - is_nullable => 1, - default_value => undef, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "entity_id" => { + data_type => "integer", + is_nullable => 0, + is_foreign_key => 1, + }, + "display_name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + "full_name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + "year_of_birth" => { + data_type => "integer", + is_nullable => 0, + }, + "postcode" => { + data_type => "varchar", + size => 16, + is_nullable => 0, + }, + latitude => { + data_type => 'decimal', + size => [ 5, 2 ], + is_nullable => 1, + default_value => undef, + }, + longitude => { + data_type => 'decimal', + size => [ 5, 2 ], + is_nullable => 1, + default_value => undef, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->belongs_to( - "entity", - "Pear::LocalLoop::Schema::Result::Entity", - "entity_id", -); +__PACKAGE__->belongs_to( "entity", "Pear::LocalLoop::Schema::Result::Entity", + "entity_id", ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/DeviceSubscription.pm b/lib/Pear/LocalLoop/Schema/Result/DeviceSubscription.pm index 0ef62ad..594eeba 100644 --- a/lib/Pear/LocalLoop/Schema/Result/DeviceSubscription.pm +++ b/lib/Pear/LocalLoop/Schema/Result/DeviceSubscription.pm @@ -8,37 +8,37 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("device_subscriptions"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "device_token_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "topic_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "device_token_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "topic_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "device_token", - "Pear::LocalLoop::Schema::Result::DeviceToken", - "device_token_id", - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "device_token", + "Pear::LocalLoop::Schema::Result::DeviceToken", + "device_token_id", + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); __PACKAGE__->belongs_to( - "topic", - "Pear::LocalLoop::Schema::Result::Topic", - "topic_id", - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "topic", + "Pear::LocalLoop::Schema::Result::Topic", + "topic_id", + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm b/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm index ebb7fe7..e97e87e 100644 --- a/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm +++ b/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm @@ -5,52 +5,54 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components( qw/ - InflateColumn::DateTime - TimeStamp - FilterColumn -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + TimeStamp + FilterColumn + / +); __PACKAGE__->table("device_tokens"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "user_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "token" => { - data_type => "varchar", - size => 200, - is_nullable => 0, - }, - "register_date" => { - data_type => "datetime", - set_on_create => 1, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "user_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "token" => { + data_type => "varchar", + size => 200, + is_nullable => 0, + }, + "register_date" => { + data_type => "datetime", + set_on_create => 1, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "user", - "Pear::LocalLoop::Schema::Result::User", - { id => "user_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "user", + "Pear::LocalLoop::Schema::Result::User", + { id => "user_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); __PACKAGE__->has_many( - "device_subscriptions", - "Pear::LocalLoop::Schema::Result::DeviceSubscription", - { "foreign.device_token_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "device_subscriptions", + "Pear::LocalLoop::Schema::Result::DeviceSubscription", + { "foreign.device_token_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); -__PACKAGE__->many_to_many('topics' => 'device_subscriptions', 'topic'); +__PACKAGE__->many_to_many( 'topics' => 'device_subscriptions', 'topic' ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Entity.pm b/lib/Pear/LocalLoop/Schema/Result/Entity.pm index b62c666..94e1cc1 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Entity.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Entity.pm @@ -8,109 +8,103 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("entities"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "type" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "type" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->might_have( - "customer", - "Pear::LocalLoop::Schema::Result::Customer" => "entity_id", -); +__PACKAGE__->might_have( "customer", + "Pear::LocalLoop::Schema::Result::Customer" => "entity_id", ); -__PACKAGE__->might_have( - "organisation", - "Pear::LocalLoop::Schema::Result::Organisation" => "entity_id", -); +__PACKAGE__->might_have( "organisation", + "Pear::LocalLoop::Schema::Result::Organisation" => "entity_id", ); -__PACKAGE__->might_have( - "user", - "Pear::LocalLoop::Schema::Result::User" => "entity_id", -); +__PACKAGE__->might_have( "user", + "Pear::LocalLoop::Schema::Result::User" => "entity_id", ); -__PACKAGE__->might_have( -"associations", - "Pear::LocalLoop::Schema::Result::EntityAssociation" => "entity_id", -); +__PACKAGE__->might_have( "associations", + "Pear::LocalLoop::Schema::Result::EntityAssociation" => "entity_id", ); -__PACKAGE__->might_have( - "postcode", - "Pear::LocalLoop::Schema::Result::EntityPostcode" => "entity_id", -); +__PACKAGE__->might_have( "postcode", + "Pear::LocalLoop::Schema::Result::EntityPostcode" => "entity_id", ); __PACKAGE__->has_many( - "purchases", - "Pear::LocalLoop::Schema::Result::Transaction", - { "foreign.buyer_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "purchases", + "Pear::LocalLoop::Schema::Result::Transaction", + { "foreign.buyer_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->has_many( - "sales", - "Pear::LocalLoop::Schema::Result::Transaction", - { "foreign.seller_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "sales", + "Pear::LocalLoop::Schema::Result::Transaction", + { "foreign.seller_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->has_many( - "global_user_medals", - "Pear::LocalLoop::Schema::Result::GlobalUserMedals", - { "foreign.entity_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "global_user_medals", + "Pear::LocalLoop::Schema::Result::GlobalUserMedals", + { "foreign.entity_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->has_many( - "global_user_medal_progress", - "Pear::LocalLoop::Schema::Result::GlobalUserMedalProgress", - { "foreign.entity_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "global_user_medal_progress", + "Pear::LocalLoop::Schema::Result::GlobalUserMedalProgress", + { "foreign.entity_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->has_many( - "org_user_medals", - "Pear::LocalLoop::Schema::Result::OrgUserMedals", - { "foreign.entity_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "org_user_medals", + "Pear::LocalLoop::Schema::Result::OrgUserMedals", + { "foreign.entity_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->has_many( - "org_user_medal_progress", - "Pear::LocalLoop::Schema::Result::OrgUserMedalProgress", - { "foreign.entity_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "org_user_medal_progress", + "Pear::LocalLoop::Schema::Result::OrgUserMedalProgress", + { "foreign.entity_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); sub name { - my $self = shift; - - if ( $self->type eq 'customer' ) { - return $self->customer->display_name; - } elsif ( $self->type eq 'organisation' ) { - return $self->organisation->name; - } else { - return "Unknown Name"; - } + my $self = shift; + + if ( $self->type eq 'customer' ) { + return $self->customer->display_name; + } + elsif ( $self->type eq 'organisation' ) { + return $self->organisation->name; + } + else { + return "Unknown Name"; + } } sub type_object { - my $self = shift; - - if ( $self->type eq 'customer' ) { - return $self->customer; - } elsif ( $self->type eq 'organisation' ) { - return $self->organisation; - } else { - return; - } + my $self = shift; + + if ( $self->type eq 'customer' ) { + return $self->customer; + } + elsif ( $self->type eq 'organisation' ) { + return $self->organisation; + } + else { + return; + } } 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm index 336cbcb..287a8b9 100644 --- a/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm @@ -8,32 +8,29 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("entity_association"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "entity_id" => { - data_type => 'integer', - is_nullable => 0, - is_foreign_key => 1, - }, - "lis" => { - data_type => 'boolean', - default_value => undef, - is_nullable => 1, - }, - "esta" => { - data_type => 'boolean', - default_value => undef, - is_nullable => 1, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "entity_id" => { + data_type => 'integer', + is_nullable => 0, + is_foreign_key => 1, + }, + "lis" => { + data_type => 'boolean', + default_value => undef, + is_nullable => 1, + }, + "esta" => { + data_type => 'boolean', + default_value => undef, + is_nullable => 1, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->belongs_to( - "entity", - "Pear::LocalLoop::Schema::Result::Entity", - "entity_id", -); +__PACKAGE__->belongs_to( "entity", "Pear::LocalLoop::Schema::Result::Entity", + "entity_id", ); diff --git a/lib/Pear/LocalLoop/Schema/Result/EntityPostcode.pm b/lib/Pear/LocalLoop/Schema/Result/EntityPostcode.pm index d36b13f..a044622 100644 --- a/lib/Pear/LocalLoop/Schema/Result/EntityPostcode.pm +++ b/lib/Pear/LocalLoop/Schema/Result/EntityPostcode.pm @@ -8,37 +8,34 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table('entities_postcodes'); __PACKAGE__->add_columns( - outcode => { - data_type => 'char', - size => 4, - is_nullable => 0, - }, - incode => { - data_type => 'char', - size => 3, - is_nullable => 0, - }, - entity_id => { - data_type => 'integer', - is_nullable => 0, - is_foreign_key => 1, - }, + outcode => { + data_type => 'char', + size => 4, + is_nullable => 0, + }, + incode => { + data_type => 'char', + size => 3, + is_nullable => 0, + }, + entity_id => { + data_type => 'integer', + is_nullable => 0, + is_foreign_key => 1, + }, ); __PACKAGE__->set_primary_key(qw/ outcode incode entity_id /); -__PACKAGE__->belongs_to( - "entity", - "Pear::LocalLoop::Schema::Result::Entity", - "entity_id", -); +__PACKAGE__->belongs_to( "entity", "Pear::LocalLoop::Schema::Result::Entity", + "entity_id", ); __PACKAGE__->belongs_to( - "gb_postcode", - "Pear::LocalLoop::Schema::Result::GbPostcode", - { - "foreign.outcode" => "self.outcode", - "foreign.incode" => "self.incode", - }, + "gb_postcode", + "Pear::LocalLoop::Schema::Result::GbPostcode", + { + "foreign.outcode" => "self.outcode", + "foreign.incode" => "self.incode", + }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/ExternalReference.pm b/lib/Pear/LocalLoop/Schema/Result/ExternalReference.pm index 15d5060..2fc9e5f 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ExternalReference.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ExternalReference.pm @@ -8,32 +8,32 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("external_references"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "name" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint([ qw/name/ ]); +__PACKAGE__->add_unique_constraint( [qw/name/] ); __PACKAGE__->has_many( - 'transactions', - "Pear::LocalLoop::Schema::Result::TransactionExternal", - { 'foreign.external_reference_id' => 'self.id' }, + 'transactions', + "Pear::LocalLoop::Schema::Result::TransactionExternal", + { 'foreign.external_reference_id' => 'self.id' }, ); __PACKAGE__->has_many( - 'organisations', - "Pear::LocalLoop::Schema::Result::OrganisationExternal", - { 'foreign.external_reference_id' => 'self.id' }, + 'organisations', + "Pear::LocalLoop::Schema::Result::OrganisationExternal", + { 'foreign.external_reference_id' => 'self.id' }, ); -1; \ No newline at end of file +1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Feedback.pm b/lib/Pear/LocalLoop/Schema/Result/Feedback.pm index d636b3d..5e722cd 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Feedback.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Feedback.pm @@ -7,81 +7,87 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("feedback"); -__PACKAGE__->load_components(qw/ - InflateColumn::DateTime - TimeStamp - FilterColumn -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + TimeStamp + FilterColumn + / +); __PACKAGE__->add_columns( - "id", - { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0 - }, - "user_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "submitted_at" => { - data_type => "datetime", - is_nullable => 0, - set_on_create => 1, - }, - "feedbacktext" => { - data_type => "text", - is_nullable => 0, - }, - "app_name" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, - "package_name" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, - "version_code" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, - "version_number" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, - "actioned" => { - data_type => "boolean", - default_value => \"false", - is_nullable => 0, - }, + "id", + { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0 + }, + "user_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "submitted_at" => { + data_type => "datetime", + is_nullable => 0, + set_on_create => 1, + }, + "feedbacktext" => { + data_type => "text", + is_nullable => 0, + }, + "app_name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + "package_name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + "version_code" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + "version_number" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + "actioned" => { + data_type => "boolean", + default_value => \"false", + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "user", - "Pear::LocalLoop::Schema::Result::User", - { id => "user_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "user", + "Pear::LocalLoop::Schema::Result::User", + { id => "user_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); -__PACKAGE__->filter_column( actioned => { - filter_to_storage => 'to_bool', -}); +__PACKAGE__->filter_column( + actioned => { + filter_to_storage => 'to_bool', + } +); sub to_bool { - my ( $self, $val ) = @_; - my $driver_name = $self->result_source->schema->storage->dbh->{Driver}->{Name}; - if ( $driver_name eq 'SQLite' ) { - return $val ? 1 : 0; - } else { - return $val ? 'true' : 'false'; - } + my ( $self, $val ) = @_; + my $driver_name = + $self->result_source->schema->storage->dbh->{Driver}->{Name}; + if ( $driver_name eq 'SQLite' ) { + return $val ? 1 : 0; + } + else { + return $val ? 'true' : 'false'; + } } 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/GbPostcode.pm b/lib/Pear/LocalLoop/Schema/Result/GbPostcode.pm index a485399..6ea4b3b 100644 --- a/lib/Pear/LocalLoop/Schema/Result/GbPostcode.pm +++ b/lib/Pear/LocalLoop/Schema/Result/GbPostcode.pm @@ -8,42 +8,39 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table('gb_postcodes'); __PACKAGE__->add_columns( - outcode => { - data_type => 'char', - size => 4, - is_nullable => 0, - }, - incode => { - data_type => 'char', - size => 3, - is_nullable => 0, - default_value => '', - }, - latitude => { - data_type => 'decimal', - size => [7,5], - is_nullable => 1, - default_value => undef, - }, - longitude => { - data_type => 'decimal', - size => [7,5], - is_nullable => 1, - default_value => undef, - }, - ward_id => { - data_type => 'integer', - is_nullable => 1, - default_value => undef, - }, + outcode => { + data_type => 'char', + size => 4, + is_nullable => 0, + }, + incode => { + data_type => 'char', + size => 3, + is_nullable => 0, + default_value => '', + }, + latitude => { + data_type => 'decimal', + size => [ 7, 5 ], + is_nullable => 1, + default_value => undef, + }, + longitude => { + data_type => 'decimal', + size => [ 7, 5 ], + is_nullable => 1, + default_value => undef, + }, + ward_id => { + data_type => 'integer', + is_nullable => 1, + default_value => undef, + }, ); __PACKAGE__->set_primary_key(qw/ outcode incode /); -__PACKAGE__->belongs_to( - "ward", - "Pear::LocalLoop::Schema::Result::GbWard", - "ward_id", -); +__PACKAGE__->belongs_to( "ward", "Pear::LocalLoop::Schema::Result::GbWard", + "ward_id", ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/GbWard.pm b/lib/Pear/LocalLoop/Schema/Result/GbWard.pm index 994c9af..f56391c 100644 --- a/lib/Pear/LocalLoop/Schema/Result/GbWard.pm +++ b/lib/Pear/LocalLoop/Schema/Result/GbWard.pm @@ -8,25 +8,25 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table('gb_wards'); __PACKAGE__->add_columns( - id => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - ward => { - data_type => 'varchar', - size => 100, - is_nullable => 0, - }, + id => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + ward => { + data_type => 'varchar', + size => 100, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key(qw/ id /); __PACKAGE__->has_many( - "postcodes", - "Pear::LocalLoop::Schema::Result::GbPostcode", - { "foreign.ward_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "postcodes", + "Pear::LocalLoop::Schema::Result::GbPostcode", + { "foreign.ward_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/GlobalMedalGroup.pm b/lib/Pear/LocalLoop/Schema/Result/GlobalMedalGroup.pm index daae226..09a4048 100644 --- a/lib/Pear/LocalLoop/Schema/Result/GlobalMedalGroup.pm +++ b/lib/Pear/LocalLoop/Schema/Result/GlobalMedalGroup.pm @@ -8,27 +8,27 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("global_medal_group"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "group_name" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "group_name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint(["group_name"]); +__PACKAGE__->add_unique_constraint( ["group_name"] ); __PACKAGE__->has_many( - "medals", - "Pear::LocalLoop::Schema::Result::GlobalMedals", - { "foreign.group_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "medals", + "Pear::LocalLoop::Schema::Result::GlobalMedals", + { "foreign.group_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/GlobalMedals.pm b/lib/Pear/LocalLoop/Schema/Result/GlobalMedals.pm index 04c8d06..09715ca 100644 --- a/lib/Pear/LocalLoop/Schema/Result/GlobalMedals.pm +++ b/lib/Pear/LocalLoop/Schema/Result/GlobalMedals.pm @@ -8,32 +8,32 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("global_medals"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "group_id" => { - data_type => "integer", - is_nullable => 0, - }, - "threshold" => { - data_type => "integer", - is_nullable => 0, - }, - "points" => { - data_type => "integer", - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "group_id" => { + data_type => "integer", + is_nullable => 0, + }, + "threshold" => { + data_type => "integer", + is_nullable => 0, + }, + "points" => { + data_type => "integer", + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "group", - "Pear::LocalLoop::Schema::Result::GlobalMedalGroup", - { id => "group_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "group", + "Pear::LocalLoop::Schema::Result::GlobalMedalGroup", + { id => "group_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/GlobalUserMedalProgress.pm b/lib/Pear/LocalLoop/Schema/Result/GlobalUserMedalProgress.pm index 7e526d2..9e18395 100644 --- a/lib/Pear/LocalLoop/Schema/Result/GlobalUserMedalProgress.pm +++ b/lib/Pear/LocalLoop/Schema/Result/GlobalUserMedalProgress.pm @@ -8,38 +8,35 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("global_user_medal_progress"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "entity_id" => { - data_type => "integer", - is_nullable => 0, - }, - "group_id" => { - data_type => "integer", - is_nullable => 0, - }, - "total" => { - data_type => "integer", - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "entity_id" => { + data_type => "integer", + is_nullable => 0, + }, + "group_id" => { + data_type => "integer", + is_nullable => 0, + }, + "total" => { + data_type => "integer", + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->belongs_to( - "entity", - "Pear::LocalLoop::Schema::Result::Entity", - "entity_id", -); +__PACKAGE__->belongs_to( "entity", "Pear::LocalLoop::Schema::Result::Entity", + "entity_id", ); __PACKAGE__->belongs_to( - "group", - "Pear::LocalLoop::Schema::Result::GlobalMedalGroup", - { id => "group_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "group", + "Pear::LocalLoop::Schema::Result::GlobalMedalGroup", + { id => "group_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/GlobalUserMedals.pm b/lib/Pear/LocalLoop/Schema/Result/GlobalUserMedals.pm index e0dc168..c716b65 100644 --- a/lib/Pear/LocalLoop/Schema/Result/GlobalUserMedals.pm +++ b/lib/Pear/LocalLoop/Schema/Result/GlobalUserMedals.pm @@ -5,55 +5,54 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components(qw/ - InflateColumn::DateTime - TimeStamp -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + TimeStamp + / +); __PACKAGE__->table("global_user_medals"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "entity_id" => { - data_type => "integer", - is_nullable => 0, - }, - "group_id" => { - data_type => "integer", - is_nullable => 0, - }, - "points" => { - data_type => "integer", - is_nullable => 0, - }, - "awarded_at" => { - data_type => "datetime", - is_nullable => 0, - set_on_create => 1, - }, - "threshold" => { - data_type => "integer", - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "entity_id" => { + data_type => "integer", + is_nullable => 0, + }, + "group_id" => { + data_type => "integer", + is_nullable => 0, + }, + "points" => { + data_type => "integer", + is_nullable => 0, + }, + "awarded_at" => { + data_type => "datetime", + is_nullable => 0, + set_on_create => 1, + }, + "threshold" => { + data_type => "integer", + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->belongs_to( - "entity", - "Pear::LocalLoop::Schema::Result::Entity", - "entity_id", -); +__PACKAGE__->belongs_to( "entity", "Pear::LocalLoop::Schema::Result::Entity", + "entity_id", ); __PACKAGE__->belongs_to( - "group", - "Pear::LocalLoop::Schema::Result::GlobalMedalGroup", - { id => "group_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "group", + "Pear::LocalLoop::Schema::Result::GlobalMedalGroup", + { id => "group_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/ImportLookup.pm b/lib/Pear/LocalLoop/Schema/Result/ImportLookup.pm index 5a49656..a16f3f8 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ImportLookup.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ImportLookup.pm @@ -8,50 +8,50 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("import_lookups"); __PACKAGE__->add_columns( - id => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - set_id => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - name => { - data_type => "varchar", - size => 255, - }, - entity_id => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, + id => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + set_id => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + name => { + data_type => "varchar", + size => 255, + }, + entity_id => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "import_set", - "Pear::LocalLoop::Schema::Result::ImportSet", - { "foreign.id" => "self.set_id" }, - { - is_deferrable => 0, - join_type => "LEFT", - on_delete => "NO ACTION", - on_update => "NO ACTION", - }, + "import_set", + "Pear::LocalLoop::Schema::Result::ImportSet", + { "foreign.id" => "self.set_id" }, + { + is_deferrable => 0, + join_type => "LEFT", + on_delete => "NO ACTION", + on_update => "NO ACTION", + }, ); __PACKAGE__->belongs_to( - "entity", - "Pear::LocalLoop::Schema::Result::Entity", - { "foreign.id" => "self.entity_id" }, - { - join_type => "LEFT", - on_delete => "NO ACTION", - on_update => "NO ACTION", - }, + "entity", + "Pear::LocalLoop::Schema::Result::Entity", + { "foreign.id" => "self.entity_id" }, + { + join_type => "LEFT", + on_delete => "NO ACTION", + on_update => "NO ACTION", + }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/ImportSet.pm b/lib/Pear/LocalLoop/Schema/Result/ImportSet.pm index 1d95af0..22a924e 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ImportSet.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ImportSet.pm @@ -5,40 +5,42 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components( qw/ - InflateColumn::DateTime - TimeStamp -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + TimeStamp + / +); __PACKAGE__->table("import_sets"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "date" => { - data_type => "datetime", - set_on_create => 1, - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "date" => { + data_type => "datetime", + set_on_create => 1, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->has_many( - "values", - "Pear::LocalLoop::Schema::Result::ImportValue", - { "foreign.set_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "values", + "Pear::LocalLoop::Schema::Result::ImportValue", + { "foreign.set_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->has_many( - "lookups", - "Pear::LocalLoop::Schema::Result::ImportLookup", - { "foreign.set_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "lookups", + "Pear::LocalLoop::Schema::Result::ImportLookup", + { "foreign.set_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/ImportValue.pm b/lib/Pear/LocalLoop/Schema/Result/ImportValue.pm index 90314c8..5da454a 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ImportValue.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ImportValue.pm @@ -5,74 +5,76 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components( qw/ - InflateColumn::DateTime -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + / +); __PACKAGE__->table("import_values"); __PACKAGE__->add_columns( - id => { - data_type => 'integer', - is_auto_increment => 1, - is_nullable => 0, - }, - set_id => { - data_type => 'integer', - is_foreign_key => 1, - is_nullable => 0, - }, - user_name => { - data_type => 'varchar', - size => 255, - }, - purchase_date => { - data_type => "datetime", - is_nullable => 0, - }, - purchase_value => { - data_type => 'varchar', - size => 255, - }, - org_name => { - data_type => 'varchar', - size => 255, - }, - transaction_id => { - data_type => 'integer', - is_foreign_key => 1, - is_nullable => 1, - }, - ignore_value => { - data_type => 'boolean', - default_value => \'false', - is_nullable => 0, - }, + id => { + data_type => 'integer', + is_auto_increment => 1, + is_nullable => 0, + }, + set_id => { + data_type => 'integer', + is_foreign_key => 1, + is_nullable => 0, + }, + user_name => { + data_type => 'varchar', + size => 255, + }, + purchase_date => { + data_type => "datetime", + is_nullable => 0, + }, + purchase_value => { + data_type => 'varchar', + size => 255, + }, + org_name => { + data_type => 'varchar', + size => 255, + }, + transaction_id => { + data_type => 'integer', + is_foreign_key => 1, + is_nullable => 1, + }, + ignore_value => { + data_type => 'boolean', + default_value => \'false', + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "import_set", - "Pear::LocalLoop::Schema::Result::ImportSet", - { "foreign.id" => "self.set_id" }, - { - is_deferrable => 0, - join_type => "LEFT", - on_delete => "NO ACTION", - on_update => "NO ACTION", - }, + "import_set", + "Pear::LocalLoop::Schema::Result::ImportSet", + { "foreign.id" => "self.set_id" }, + { + is_deferrable => 0, + join_type => "LEFT", + on_delete => "NO ACTION", + on_update => "NO ACTION", + }, ); __PACKAGE__->belongs_to( - "transaction", - "Pear::LocalLoop::Schema::Result::Transaction", - { "foreign.id" => "self.transaction_id" }, - { - join_type => "LEFT", - on_delete => "NO ACTION", - on_update => "NO ACTION", - }, + "transaction", + "Pear::LocalLoop::Schema::Result::Transaction", + { "foreign.id" => "self.transaction_id" }, + { + join_type => "LEFT", + on_delete => "NO ACTION", + on_update => "NO ACTION", + }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Leaderboard.pm b/lib/Pear/LocalLoop/Schema/Result/Leaderboard.pm index 7c122d7..bceb7d0 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Leaderboard.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Leaderboard.pm @@ -10,242 +10,271 @@ use DateTime; __PACKAGE__->table("leaderboards"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "name" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, - "type" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + "type" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint(["type"]); +__PACKAGE__->add_unique_constraint( ["type"] ); __PACKAGE__->has_many( - "sets", - "Pear::LocalLoop::Schema::Result::LeaderboardSet", - { "foreign.leaderboard_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "sets", + "Pear::LocalLoop::Schema::Result::LeaderboardSet", + { "foreign.leaderboard_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); sub create_new { - my $self = shift; - my $start = shift; - - my $type = $self->type; - - if ( $type eq 'daily_total' ) { - return $self->_create_total_set( $start, $start->clone->add( days => 1 ) ); - } elsif ( $type eq 'weekly_total' ) { - return $self->_create_total_set( $start, $start->clone->add( days => 7 ) ); - } elsif ( $type eq 'monthly_total' ) { - return $self->_create_total_set( $start, $start->clone->add( months => 1 ) ); - } elsif ( $type eq 'all_time_total' ) { - return $self->_create_total_all_time( $start ); - } elsif ( $type eq 'daily_count' ) { - return $self->_create_count_set( $start, $start->clone->add( days => 1 ) ); - } elsif ( $type eq 'weekly_count' ) { - return $self->_create_count_set( $start, $start->clone->add( days => 7 ) ); - } elsif ( $type eq 'monthly_count' ) { - return $self->_create_count_set( $start, $start->clone->add( months => 1 ) ); - } elsif ( $type eq 'all_time_count' ) { - return $self->_create_count_all_time( $start ); - } - warn "Unrecognised type"; - return $self; + my $self = shift; + my $start = shift; + + my $type = $self->type; + + if ( $type eq 'daily_total' ) { + return $self->_create_total_set( $start, + $start->clone->add( days => 1 ) ); + } + elsif ( $type eq 'weekly_total' ) { + return $self->_create_total_set( $start, + $start->clone->add( days => 7 ) ); + } + elsif ( $type eq 'monthly_total' ) { + return $self->_create_total_set( $start, + $start->clone->add( months => 1 ) ); + } + elsif ( $type eq 'all_time_total' ) { + return $self->_create_total_all_time($start); + } + elsif ( $type eq 'daily_count' ) { + return $self->_create_count_set( $start, + $start->clone->add( days => 1 ) ); + } + elsif ( $type eq 'weekly_count' ) { + return $self->_create_count_set( $start, + $start->clone->add( days => 7 ) ); + } + elsif ( $type eq 'monthly_count' ) { + return $self->_create_count_set( $start, + $start->clone->add( months => 1 ) ); + } + elsif ( $type eq 'all_time_count' ) { + return $self->_create_count_all_time($start); + } + warn "Unrecognised type"; + return $self; } sub _get_customer_rs { - my $self = shift; - return $self->result_source->schema->resultset('Entity')->search({ - type => 'customer', - }); + my $self = shift; + return $self->result_source->schema->resultset('Entity')->search( + { + type => 'customer', + } + ); } sub _set_position_and_trend { - my ( $self, @leaderboard ) = @_; - - # Sort numerically descending - @leaderboard = sort { $b->{value} <=> $a->{value} } @leaderboard; + my ( $self, @leaderboard ) = @_; - my $position = 0; + # Sort numerically descending + @leaderboard = sort { $b->{value} <=> $a->{value} } @leaderboard; - my $previous_board = $self->get_latest; + my $position = 0; - if ( defined $previous_board ) { - $previous_board = $previous_board->values; - } - - for my $lb_val ( @leaderboard ) { - $position++; - $lb_val->{position} = $position; - - my $previous_value; + my $previous_board = $self->get_latest; if ( defined $previous_board ) { - $previous_value = $previous_board->find({ entity_id => $lb_val->{entity_id} }); + $previous_board = $previous_board->values; } - my $trend; - - if ( ! defined $previous_value ) { - $trend = 0; - } elsif ( $previous_value->position > $position ) { - $trend = -1; - } elsif ( $previous_value->position < $position ) { - $trend = 1; - } else { - $trend = 0; + for my $lb_val (@leaderboard) { + $position++; + $lb_val->{position} = $position; + + my $previous_value; + + if ( defined $previous_board ) { + $previous_value = + $previous_board->find( { entity_id => $lb_val->{entity_id} } ); + } + + my $trend; + + if ( !defined $previous_value ) { + $trend = 0; + } + elsif ( $previous_value->position > $position ) { + $trend = -1; + } + elsif ( $previous_value->position < $position ) { + $trend = 1; + } + else { + $trend = 0; + } + + $lb_val->{trend} = $trend; } - $lb_val->{trend} = $trend; - } - - return @leaderboard; + return @leaderboard; } sub _create_total_set { - my ( $self, $start, $end ) = @_; + my ( $self, $start, $end ) = @_; - my $user_rs = $self->_get_customer_rs; + my $user_rs = $self->_get_customer_rs; - my @leaderboard; + my @leaderboard; - while ( my $user_result = $user_rs->next ) { - my $transaction_rs = $user_result->purchases->search_between( $start, $end ); + while ( my $user_result = $user_rs->next ) { + my $transaction_rs = + $user_result->purchases->search_between( $start, $end ); - my $transaction_sum = $transaction_rs->get_column('value')->sum; + my $transaction_sum = $transaction_rs->get_column('value')->sum; - push @leaderboard, { - entity_id => $user_result->id, - value => $transaction_sum || 0, - }; - } + push @leaderboard, + { + entity_id => $user_result->id, + value => $transaction_sum || 0, + }; + } - @leaderboard = $self->_set_position_and_trend(@leaderboard); + @leaderboard = $self->_set_position_and_trend(@leaderboard); - $self->create_related( - 'sets', - { - date => $start, - values => \@leaderboard, - }, - ); + $self->create_related( + 'sets', + { + date => $start, + values => \@leaderboard, + }, + ); - return $self; + return $self; } sub _create_count_set { - my ( $self, $start, $end ) = @_; + my ( $self, $start, $end ) = @_; - my $user_rs = $self->_get_customer_rs; + my $user_rs = $self->_get_customer_rs; - my @leaderboard; + my @leaderboard; - while ( my $user_result = $user_rs->next ) { - my $transaction_rs = $user_result->purchases->search_between( $start, $end ); + while ( my $user_result = $user_rs->next ) { + my $transaction_rs = + $user_result->purchases->search_between( $start, $end ); - my $transaction_count = $transaction_rs->count; + my $transaction_count = $transaction_rs->count; - push @leaderboard, { - entity_id => $user_result->id, - value => $transaction_count || 0, - }; - } + push @leaderboard, + { + entity_id => $user_result->id, + value => $transaction_count || 0, + }; + } - @leaderboard = $self->_set_position_and_trend(@leaderboard); + @leaderboard = $self->_set_position_and_trend(@leaderboard); - $self->create_related( - 'sets', - { - date => $start, - values => \@leaderboard, - }, - ); + $self->create_related( + 'sets', + { + date => $start, + values => \@leaderboard, + }, + ); - return $self; + return $self; } sub _create_total_all_time { - my ( $self, $end ) = @_; + my ( $self, $end ) = @_; - my $user_rs = $self->_get_customer_rs; - - my @leaderboard; + my $user_rs = $self->_get_customer_rs; - while ( my $user_result = $user_rs->next ) { - my $transaction_rs = $user_result->purchases->search_before( $end ); + my @leaderboard; - my $transaction_sum = $transaction_rs->get_column('value')->sum; + while ( my $user_result = $user_rs->next ) { + my $transaction_rs = $user_result->purchases->search_before($end); - push @leaderboard, { - entity_id => $user_result->id, - value => $transaction_sum || 0, - }; - } + my $transaction_sum = $transaction_rs->get_column('value')->sum; - @leaderboard = $self->_set_position_and_trend(@leaderboard); + push @leaderboard, + { + entity_id => $user_result->id, + value => $transaction_sum || 0, + }; + } - $self->create_related( - 'sets', - { - date => $end, - values => \@leaderboard, - }, - ); + @leaderboard = $self->_set_position_and_trend(@leaderboard); - return $self; + $self->create_related( + 'sets', + { + date => $end, + values => \@leaderboard, + }, + ); + + return $self; } sub _create_count_all_time { - my ( $self, $end ) = @_; + my ( $self, $end ) = @_; - my $user_rs = $self->_get_customer_rs; + my $user_rs = $self->_get_customer_rs; - my @leaderboard; + my @leaderboard; - while ( my $user_result = $user_rs->next ) { - my $transaction_rs = $user_result->purchases->search_before( $end ); + while ( my $user_result = $user_rs->next ) { + my $transaction_rs = $user_result->purchases->search_before($end); - my $transaction_count = $transaction_rs->count; + my $transaction_count = $transaction_rs->count; - push @leaderboard, { - entity_id => $user_result->id, - value => $transaction_count || 0, - }; - } + push @leaderboard, + { + entity_id => $user_result->id, + value => $transaction_count || 0, + }; + } - @leaderboard = $self->_set_position_and_trend(@leaderboard); + @leaderboard = $self->_set_position_and_trend(@leaderboard); - $self->create_related( - 'sets', - { - date => $end, - values => \@leaderboard, - }, - ); + $self->create_related( + 'sets', + { + date => $end, + values => \@leaderboard, + }, + ); - return $self; + return $self; } sub get_latest { - my $self = shift; + my $self = shift; - my $latest = $self->search_related('sets', {}, { - order_by => { -desc => 'date' }, - })->first; + my $latest = $self->search_related( + 'sets', + {}, + { + order_by => { -desc => 'date' }, + } + )->first; - return $latest; + return $latest; } 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/LeaderboardSet.pm b/lib/Pear/LocalLoop/Schema/Result/LeaderboardSet.pm index f1a072f..0c65966 100644 --- a/lib/Pear/LocalLoop/Schema/Result/LeaderboardSet.pm +++ b/lib/Pear/LocalLoop/Schema/Result/LeaderboardSet.pm @@ -5,48 +5,50 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components( qw/ - InflateColumn::DateTime -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + / +); __PACKAGE__->table("leaderboard_sets"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "leaderboard_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "date" => { - data_type => "datetime", - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "leaderboard_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "date" => { + data_type => "datetime", + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "leaderboard", - "Pear::LocalLoop::Schema::Result::Leaderboard", - { "foreign.id" => "self.leaderboard_id" }, - { - is_deferrable => 0, - join_type => "LEFT", - on_delete => "NO ACTION", - on_update => "NO ACTION", - }, + "leaderboard", + "Pear::LocalLoop::Schema::Result::Leaderboard", + { "foreign.id" => "self.leaderboard_id" }, + { + is_deferrable => 0, + join_type => "LEFT", + on_delete => "NO ACTION", + on_update => "NO ACTION", + }, ); __PACKAGE__->has_many( - "values", - "Pear::LocalLoop::Schema::Result::LeaderboardValue", - { "foreign.set_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "values", + "Pear::LocalLoop::Schema::Result::LeaderboardValue", + { "foreign.set_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/LeaderboardValue.pm b/lib/Pear/LocalLoop/Schema/Result/LeaderboardValue.pm index 8c08f1c..b7df6bf 100644 --- a/lib/Pear/LocalLoop/Schema/Result/LeaderboardValue.pm +++ b/lib/Pear/LocalLoop/Schema/Result/LeaderboardValue.pm @@ -8,62 +8,62 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("leaderboard_values"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "entity_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "set_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "position" => { - data_type => "integer", - is_nullable => 0, - }, - "value" => { - data_type => "numeric", - size => [ 100, 0 ], - is_nullable => 0, - }, - "trend" => { - data_type => "integer", - default_value => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "entity_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "set_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "position" => { + data_type => "integer", + is_nullable => 0, + }, + "value" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "trend" => { + data_type => "integer", + default_value => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint([qw/ entity_id set_id /]); +__PACKAGE__->add_unique_constraint( [qw/ entity_id set_id /] ); __PACKAGE__->belongs_to( - "set", - "Pear::LocalLoop::Schema::Result::LeaderboardSet", - { "foreign.id" => "self.set_id" }, - { - is_deferrable => 0, - join_type => "LEFT", - on_delete => "NO ACTION", - on_update => "NO ACTION", - }, + "set", + "Pear::LocalLoop::Schema::Result::LeaderboardSet", + { "foreign.id" => "self.set_id" }, + { + is_deferrable => 0, + join_type => "LEFT", + on_delete => "NO ACTION", + on_update => "NO ACTION", + }, ); __PACKAGE__->belongs_to( - "entity", - "Pear::LocalLoop::Schema::Result::Entity", - { "foreign.id" => "self.entity_id" }, - { - is_deferrable => 0, - join_type => "LEFT", - on_delete => "NO ACTION", - on_update => "NO ACTION", - }, + "entity", + "Pear::LocalLoop::Schema::Result::Entity", + { "foreign.id" => "self.entity_id" }, + { + is_deferrable => 0, + join_type => "LEFT", + on_delete => "NO ACTION", + on_update => "NO ACTION", + }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/OrgMedalGroup.pm b/lib/Pear/LocalLoop/Schema/Result/OrgMedalGroup.pm index eb945d2..0ae8844 100644 --- a/lib/Pear/LocalLoop/Schema/Result/OrgMedalGroup.pm +++ b/lib/Pear/LocalLoop/Schema/Result/OrgMedalGroup.pm @@ -8,27 +8,27 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("org_medal_group"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "group_name" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "group_name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint(["group_name"]); +__PACKAGE__->add_unique_constraint( ["group_name"] ); __PACKAGE__->has_many( - "medals", - "Pear::LocalLoop::Schema::Result::OrgMedals", - { "foreign.group_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "medals", + "Pear::LocalLoop::Schema::Result::OrgMedals", + { "foreign.group_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/OrgMedals.pm b/lib/Pear/LocalLoop/Schema/Result/OrgMedals.pm index 4b3f9e5..1a81e44 100644 --- a/lib/Pear/LocalLoop/Schema/Result/OrgMedals.pm +++ b/lib/Pear/LocalLoop/Schema/Result/OrgMedals.pm @@ -8,32 +8,32 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("org_medals"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "group_id" => { - data_type => "integer", - is_nullable => 0, - }, - "threshold" => { - data_type => "integer", - is_nullable => 0, - }, - "points" => { - data_type => "integer", - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "group_id" => { + data_type => "integer", + is_nullable => 0, + }, + "threshold" => { + data_type => "integer", + is_nullable => 0, + }, + "points" => { + data_type => "integer", + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "group", - "Pear::LocalLoop::Schema::Result::OrgMedalGroup", - { id => "group_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "group", + "Pear::LocalLoop::Schema::Result::OrgMedalGroup", + { id => "group_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/OrgUserMedalProgress.pm b/lib/Pear/LocalLoop/Schema/Result/OrgUserMedalProgress.pm index df0ff1e..11d6dff 100644 --- a/lib/Pear/LocalLoop/Schema/Result/OrgUserMedalProgress.pm +++ b/lib/Pear/LocalLoop/Schema/Result/OrgUserMedalProgress.pm @@ -8,38 +8,35 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("org_user_medal_progress"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "entity_id" => { - data_type => "integer", - is_nullable => 0, - }, - "group_id" => { - data_type => "integer", - is_nullable => 0, - }, - "total" => { - data_type => "integer", - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "entity_id" => { + data_type => "integer", + is_nullable => 0, + }, + "group_id" => { + data_type => "integer", + is_nullable => 0, + }, + "total" => { + data_type => "integer", + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->belongs_to( - "entity", - "Pear::LocalLoop::Schema::Result::Entity", - "entity_id", -); +__PACKAGE__->belongs_to( "entity", "Pear::LocalLoop::Schema::Result::Entity", + "entity_id", ); __PACKAGE__->belongs_to( - "group", - "Pear::LocalLoop::Schema::Result::OrgMedalGroup", - { id => "group_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "group", + "Pear::LocalLoop::Schema::Result::OrgMedalGroup", + { id => "group_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/OrgUserMedals.pm b/lib/Pear/LocalLoop/Schema/Result/OrgUserMedals.pm index cd8671e..91ea253 100644 --- a/lib/Pear/LocalLoop/Schema/Result/OrgUserMedals.pm +++ b/lib/Pear/LocalLoop/Schema/Result/OrgUserMedals.pm @@ -5,55 +5,54 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components(qw/ - InflateColumn::DateTime - TimeStamp -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + TimeStamp + / +); __PACKAGE__->table("org_user_medals"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "entity_id" => { - data_type => "integer", - is_nullable => 0, - }, - "group_id" => { - data_type => "integer", - is_nullable => 0, - }, - "points" => { - data_type => "integer", - is_nullable => 0, - }, - "awarded_at" => { - data_type => "datetime", - is_nullable => 0, - set_on_create => 1, - }, - "threshold" => { - data_type => "integer", - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "entity_id" => { + data_type => "integer", + is_nullable => 0, + }, + "group_id" => { + data_type => "integer", + is_nullable => 0, + }, + "points" => { + data_type => "integer", + is_nullable => 0, + }, + "awarded_at" => { + data_type => "datetime", + is_nullable => 0, + set_on_create => 1, + }, + "threshold" => { + data_type => "integer", + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->belongs_to( - "entity", - "Pear::LocalLoop::Schema::Result::Entity", - "entity_id", -); +__PACKAGE__->belongs_to( "entity", "Pear::LocalLoop::Schema::Result::Entity", + "entity_id", ); __PACKAGE__->belongs_to( - "group", - "Pear::LocalLoop::Schema::Result::OrgMedalGroup", - { id => "group_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "group", + "Pear::LocalLoop::Schema::Result::OrgMedalGroup", + { id => "group_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm index ce05e53..06be273 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm @@ -5,172 +5,166 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components("InflateColumn::DateTime", "FilterColumn"); +__PACKAGE__->load_components( "InflateColumn::DateTime", "FilterColumn" ); __PACKAGE__->table("organisations"); __PACKAGE__->add_columns( - id => { - data_type => 'integer', - is_auto_increment => 1, - is_nullable => 0, - }, - entity_id => { - data_type => 'integer', - is_nullable => 0, - is_foreign_key => 1, - }, - name => { - data_type => 'varchar', - size => 255, - is_nullable => 0, - }, - street_name => { - data_type => 'text', - is_nullable => 1, - }, - town => { - data_type => 'varchar', - size => 255, - is_nullable => 0, - }, - postcode => { - data_type => 'varchar', - size => 16, - is_nullable => 1, - }, - country => { - data_type => 'varchar', - size => 255, - is_nullable => 1, - }, - # Stores codes based on https://www.ons.gov.uk/methodology/classificationsandstandards/ukstandardindustrialclassificationofeconomicactivities/uksic2007 - sector => { - data_type => 'varchar', - size => 1, - is_nullable => 1, - }, - pending => { - data_type => 'boolean', - default_value => \"false", - is_nullable => 0, - }, - is_local => { - data_type => 'boolean', - default_value => undef, - is_nullable => 1, - }, - is_fair => { - data_type => 'boolean', - default_value => undef, - is_nullable => 1, - }, - submitted_by_id => { - data_type => 'integer', - is_nullable => 1, - }, - latitude => { - data_type => 'decimal', - size => [ 8, 5 ], - is_nullable => 1, - default_value => undef, - }, - longitude => { - data_type => 'decimal', - size => [ 8, 5 ], - is_nullable => 1, - default_value => undef, - }, - type_id => { - data_type => 'integer', - is_nullable => 1, - is_foreign_key => 1, - }, - social_type_id => { - data_type => 'integer', - is_nullable => 1, - is_foreign_key => 1, - }, - is_anchor => { - data_type => 'boolean', - is_nullable => 0, - default_value => \'FALSE', - } + id => { + data_type => 'integer', + is_auto_increment => 1, + is_nullable => 0, + }, + entity_id => { + data_type => 'integer', + is_nullable => 0, + is_foreign_key => 1, + }, + name => { + data_type => 'varchar', + size => 255, + is_nullable => 0, + }, + street_name => { + data_type => 'text', + is_nullable => 1, + }, + town => { + data_type => 'varchar', + size => 255, + is_nullable => 0, + }, + postcode => { + data_type => 'varchar', + size => 16, + is_nullable => 1, + }, + country => { + data_type => 'varchar', + size => 255, + is_nullable => 1, + }, + +# Stores codes based on https://www.ons.gov.uk/methodology/classificationsandstandards/ukstandardindustrialclassificationofeconomicactivities/uksic2007 + sector => { + data_type => 'varchar', + size => 1, + is_nullable => 1, + }, + pending => { + data_type => 'boolean', + default_value => \"false", + is_nullable => 0, + }, + is_local => { + data_type => 'boolean', + default_value => undef, + is_nullable => 1, + }, + is_fair => { + data_type => 'boolean', + default_value => undef, + is_nullable => 1, + }, + submitted_by_id => { + data_type => 'integer', + is_nullable => 1, + }, + latitude => { + data_type => 'decimal', + size => [ 8, 5 ], + is_nullable => 1, + default_value => undef, + }, + longitude => { + data_type => 'decimal', + size => [ 8, 5 ], + is_nullable => 1, + default_value => undef, + }, + type_id => { + data_type => 'integer', + is_nullable => 1, + is_foreign_key => 1, + }, + social_type_id => { + data_type => 'integer', + is_nullable => 1, + is_foreign_key => 1, + }, + is_anchor => { + data_type => 'boolean', + is_nullable => 0, + default_value => \'FALSE', + } ); __PACKAGE__->set_primary_key('id'); -__PACKAGE__->belongs_to( - "entity", - "Pear::LocalLoop::Schema::Result::Entity", - "entity_id", -); +__PACKAGE__->belongs_to( "entity", "Pear::LocalLoop::Schema::Result::Entity", + "entity_id", ); -__PACKAGE__->belongs_to( - "organisation_type", - "Pear::LocalLoop::Schema::Result::OrganisationType", - "type_id", -); +__PACKAGE__->belongs_to( "organisation_type", + "Pear::LocalLoop::Schema::Result::OrganisationType", "type_id", ); -__PACKAGE__->belongs_to( - "social_type", - "Pear::LocalLoop::Schema::Result::OrganisationSocialType", - "social_type_id", -); +__PACKAGE__->belongs_to( "social_type", + "Pear::LocalLoop::Schema::Result::OrganisationSocialType", + "social_type_id", ); __PACKAGE__->has_many( - "external_reference", - "Pear::LocalLoop::Schema::Result::OrganisationExternal", - { 'foreign.org_id' => 'self.id' }, + "external_reference", + "Pear::LocalLoop::Schema::Result::OrganisationExternal", + { 'foreign.org_id' => 'self.id' }, ); __PACKAGE__->has_many( - "payroll", - "Pear::LocalLoop::Schema::Result::OrganisationPayroll", - { "foreign.org_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "payroll", + "Pear::LocalLoop::Schema::Result::OrganisationPayroll", + { "foreign.org_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->filter_column( - pending => { - filter_to_storage => 'to_bool', - }, - is_local => { - filter_to_storage => 'to_bool', - }, - is_anchor => { - filter_to_storage => 'to_bool', - } + pending => { + filter_to_storage => 'to_bool', + }, + is_local => { + filter_to_storage => 'to_bool', + }, + is_anchor => { + filter_to_storage => 'to_bool', + } ); # Only works when calling ->deploy, but atleast helps for tests sub sqlt_deploy_hook { - my ($source_instance, $sqlt_table) = @_; - my $pending_field = $sqlt_table->get_field('pending'); - if ($sqlt_table->schema->translator->producer_type =~ /SQLite$/) { - $pending_field->{default_value} = 0; - } - else { - $pending_field->{default_value} = \"false"; - } + my ( $source_instance, $sqlt_table ) = @_; + my $pending_field = $sqlt_table->get_field('pending'); + if ( $sqlt_table->schema->translator->producer_type =~ /SQLite$/ ) { + $pending_field->{default_value} = 0; + } + else { + $pending_field->{default_value} = \"false"; + } } sub to_bool { - my ($self, $val) = @_; - return if !defined $val; - my $driver_name = $self->result_source->schema->storage->dbh->{Driver}->{Name}; - if ($driver_name eq 'SQLite') { - return $val ? 1 : 0; - } - else { - return $val ? 'true' : 'false'; - } + my ( $self, $val ) = @_; + return if !defined $val; + my $driver_name = + $self->result_source->schema->storage->dbh->{Driver}->{Name}; + if ( $driver_name eq 'SQLite' ) { + return $val ? 1 : 0; + } + else { + return $val ? 'true' : 'false'; + } } sub user { - my $self = shift; + my $self = shift; - return $self->entity->user; + return $self->entity->user; } 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/OrganisationExternal.pm b/lib/Pear/LocalLoop/Schema/Result/OrganisationExternal.pm index aadbec5..a4537af 100644 --- a/lib/Pear/LocalLoop/Schema/Result/OrganisationExternal.pm +++ b/lib/Pear/LocalLoop/Schema/Result/OrganisationExternal.pm @@ -8,42 +8,42 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("organisations_external"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "org_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "external_reference_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "external_id" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - } + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "org_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "external_reference_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "external_id" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + } ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint([ qw/external_reference_id external_id/ ]); +__PACKAGE__->add_unique_constraint( [qw/external_reference_id external_id/] ); __PACKAGE__->belongs_to( - "organisation", - "Pear::LocalLoop::Schema::Result::Organisation", - { 'foreign.id' => 'self.org_id' }, + "organisation", + "Pear::LocalLoop::Schema::Result::Organisation", + { 'foreign.id' => 'self.org_id' }, ); __PACKAGE__->belongs_to( - "external_reference", - "Pear::LocalLoop::Schema::Result::ExternalReference", - { 'foreign.id' => 'self.external_reference_id' }, + "external_reference", + "Pear::LocalLoop::Schema::Result::ExternalReference", + { 'foreign.id' => 'self.external_reference_id' }, ); -1; \ No newline at end of file +1; diff --git a/lib/Pear/LocalLoop/Schema/Result/OrganisationPayroll.pm b/lib/Pear/LocalLoop/Schema/Result/OrganisationPayroll.pm index c60d458..2fc992a 100644 --- a/lib/Pear/LocalLoop/Schema/Result/OrganisationPayroll.pm +++ b/lib/Pear/LocalLoop/Schema/Result/OrganisationPayroll.pm @@ -5,79 +5,78 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components(qw/ - InflateColumn::DateTime - TimeStamp -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + TimeStamp + / +); __PACKAGE__->table("organisation_payroll"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "org_id" => { - data_type => 'integer', - is_nullable => 0, - is_foreign_key => 1, - }, - "submitted_at" => { - data_type => "datetime", - is_nullable => 0, - set_on_create => 1, - }, - "entry_period" => { - data_type => "datetime", - is_nullable => 0, - }, - "employee_amount" => { - data_type => "integer", - is_nullable => 0, - }, - "local_employee_amount" => { - data_type => "integer", - is_nullable => 0, - }, - "gross_payroll" => { - data_type => "numeric", - size => [ 100, 0 ], - is_nullable => 0, - }, - "payroll_income_tax" => { - data_type => "numeric", - size => [ 100, 0 ], - is_nullable => 0, - }, - "payroll_employee_ni" => { - data_type => "numeric", - size => [ 100, 0 ], - is_nullable => 0, - }, - "payroll_employer_ni" => { - data_type => "numeric", - size => [ 100, 0 ], - is_nullable => 0, - }, - "payroll_total_pension" => { - data_type => "numeric", - size => [ 100, 0 ], - is_nullable => 0, - }, - "payroll_other_benefit" => { - data_type => "numeric", - size => [ 100, 0 ], - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "org_id" => { + data_type => 'integer', + is_nullable => 0, + is_foreign_key => 1, + }, + "submitted_at" => { + data_type => "datetime", + is_nullable => 0, + set_on_create => 1, + }, + "entry_period" => { + data_type => "datetime", + is_nullable => 0, + }, + "employee_amount" => { + data_type => "integer", + is_nullable => 0, + }, + "local_employee_amount" => { + data_type => "integer", + is_nullable => 0, + }, + "gross_payroll" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "payroll_income_tax" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "payroll_employee_ni" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "payroll_employer_ni" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "payroll_total_pension" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "payroll_other_benefit" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->belongs_to( - "organisation", - "Pear::LocalLoop::Schema::Result::Organisation", - "org_id", -); +__PACKAGE__->belongs_to( "organisation", + "Pear::LocalLoop::Schema::Result::Organisation", "org_id", ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/OrganisationSocialType.pm b/lib/Pear/LocalLoop/Schema/Result/OrganisationSocialType.pm index e0d1645..2c30630 100644 --- a/lib/Pear/LocalLoop/Schema/Result/OrganisationSocialType.pm +++ b/lib/Pear/LocalLoop/Schema/Result/OrganisationSocialType.pm @@ -8,32 +8,32 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("organisation_social_types"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "key" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, - "name" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - } + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "key" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + "name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + } ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint([ qw/key/ ]); +__PACKAGE__->add_unique_constraint( [qw/key/] ); __PACKAGE__->has_many( - "organisations", - "Pear::LocalLoop::Schema::Result::Organisation", - { 'foreign.social_type_id' => 'self.id' }, + "organisations", + "Pear::LocalLoop::Schema::Result::Organisation", + { 'foreign.social_type_id' => 'self.id' }, ); 1; -1; \ No newline at end of file +1; diff --git a/lib/Pear/LocalLoop/Schema/Result/OrganisationType.pm b/lib/Pear/LocalLoop/Schema/Result/OrganisationType.pm index f7967d6..1241517 100644 --- a/lib/Pear/LocalLoop/Schema/Result/OrganisationType.pm +++ b/lib/Pear/LocalLoop/Schema/Result/OrganisationType.pm @@ -8,31 +8,31 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("organisation_types"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "key" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, - "name" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - } + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "key" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + "name" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + } ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint([ qw/key/ ]); +__PACKAGE__->add_unique_constraint( [qw/key/] ); __PACKAGE__->has_many( - "organisations", - "Pear::LocalLoop::Schema::Result::Organisation", - { 'foreign.type_id' => 'self.id' }, + "organisations", + "Pear::LocalLoop::Schema::Result::Organisation", + { 'foreign.type_id' => 'self.id' }, ); -1; \ No newline at end of file +1; diff --git a/lib/Pear/LocalLoop/Schema/Result/SessionToken.pm b/lib/Pear/LocalLoop/Schema/Result/SessionToken.pm index 17eb162..faf55bb 100644 --- a/lib/Pear/LocalLoop/Schema/Result/SessionToken.pm +++ b/lib/Pear/LocalLoop/Schema/Result/SessionToken.pm @@ -8,32 +8,32 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("session_tokens"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "token" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, - "user_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "token" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + "user_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint(["token"]); +__PACKAGE__->add_unique_constraint( ["token"] ); __PACKAGE__->belongs_to( - "user", - "Pear::LocalLoop::Schema::Result::User", - { id => "user_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "user", + "Pear::LocalLoop::Schema::Result::User", + { id => "user_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Topic.pm b/lib/Pear/LocalLoop/Schema/Result/Topic.pm index cae97bd..aab2684 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Topic.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Topic.pm @@ -5,36 +5,41 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components( qw/ - InflateColumn::DateTime - TimeStamp - FilterColumn -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + TimeStamp + FilterColumn + / +); __PACKAGE__->table("topics"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "name" => { - data_type => "varchar", - size => 200, - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "name" => { + data_type => "varchar", + size => 200, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->has_many( - "device_subscriptions", - "Pear::LocalLoop::Schema::Result::DeviceSubscription", - { "foreign.topic_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "device_subscriptions", + "Pear::LocalLoop::Schema::Result::DeviceSubscription", + { "foreign.topic_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); -__PACKAGE__->many_to_many('device_tokens' => 'device_subscriptions', 'device_token'); +__PACKAGE__->many_to_many( + 'device_tokens' => 'device_subscriptions', + 'device_token' +); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm index 3a49f2e..d951d9e 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm @@ -5,80 +5,81 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components(qw/ - InflateColumn::DateTime - TimeStamp -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + TimeStamp + / +); __PACKAGE__->table("transactions"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "buyer_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "seller_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "value" => { - data_type => "numeric", - size => [ 100, 0 ], - is_nullable => 0, - }, - "proof_image" => { - data_type => "text", - is_nullable => 1, - }, - "submitted_at" => { - data_type => "datetime", - is_nullable => 0, - set_on_create => 1, - }, - "purchase_time" => { - data_type => "datetime", - timezone => "UTC", - is_nullable => 0, - set_on_create => 1, - }, - "essential" => { - data_type => "boolean", - default_value => \"false", - is_nullable => 0, - }, - distance => { - data_type => 'numeric', - size => [15], - is_nullable => 1, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "buyer_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "seller_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "value" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "proof_image" => { + data_type => "text", + is_nullable => 1, + }, + "submitted_at" => { + data_type => "datetime", + is_nullable => 0, + set_on_create => 1, + }, + "purchase_time" => { + data_type => "datetime", + timezone => "UTC", + is_nullable => 0, + set_on_create => 1, + }, + "essential" => { + data_type => "boolean", + default_value => \"false", + is_nullable => 0, + }, + distance => { + data_type => 'numeric', + size => [15], + is_nullable => 1, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "buyer", - "Pear::LocalLoop::Schema::Result::Entity", - { id => "buyer_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "buyer", + "Pear::LocalLoop::Schema::Result::Entity", + { id => "buyer_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); __PACKAGE__->belongs_to( - "seller", - "Pear::LocalLoop::Schema::Result::Entity", - { id => "seller_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "seller", + "Pear::LocalLoop::Schema::Result::Entity", + { id => "seller_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); -__PACKAGE__->might_have( - "category", - "Pear::LocalLoop::Schema::Result::TransactionCategory" => "transaction_id", +__PACKAGE__->might_have( "category", + "Pear::LocalLoop::Schema::Result::TransactionCategory" => "transaction_id", ); __PACKAGE__->has_one( @@ -94,13 +95,14 @@ __PACKAGE__->has_many( ); sub sqlt_deploy_hook { - my ( $source_instance, $sqlt_table ) = @_; - my $pending_field = $sqlt_table->get_field('essential'); - if ( $sqlt_table->schema->translator->producer_type =~ /SQLite$/ ) { - $pending_field->{default_value} = 0; - } else { - $pending_field->{default_value} = \"false"; - } + my ( $source_instance, $sqlt_table ) = @_; + my $pending_field = $sqlt_table->get_field('essential'); + if ( $sqlt_table->schema->translator->producer_type =~ /SQLite$/ ) { + $pending_field->{default_value} = 0; + } + else { + $pending_field->{default_value} = \"false"; + } } 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/TransactionCategory.pm b/lib/Pear/LocalLoop/Schema/Result/TransactionCategory.pm index 87c2462..caf0abb 100644 --- a/lib/Pear/LocalLoop/Schema/Result/TransactionCategory.pm +++ b/lib/Pear/LocalLoop/Schema/Result/TransactionCategory.pm @@ -8,32 +8,28 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("transaction_category"); __PACKAGE__->add_columns( - "category_id" => { - data_type => "integer", - is_nullable => 0, - is_foreign_key => 1, - }, - "transaction_id" => { - data_type => 'integer', - is_nullable => 0, - is_foreign_key => 1, - }, + "category_id" => { + data_type => "integer", + is_nullable => 0, + is_foreign_key => 1, + }, + "transaction_id" => { + data_type => 'integer', + is_nullable => 0, + is_foreign_key => 1, + }, ); -__PACKAGE__->add_unique_constraint(["transaction_id"]); +__PACKAGE__->add_unique_constraint( ["transaction_id"] ); __PACKAGE__->belongs_to( - "category", - "Pear::LocalLoop::Schema::Result::Category", - "category_id", - { cascade_delete => 0 }, + "category", "Pear::LocalLoop::Schema::Result::Category", + "category_id", { cascade_delete => 0 }, ); __PACKAGE__->belongs_to( - "transaction", - "Pear::LocalLoop::Schema::Result::Transaction", - "transaction_id", - { cascade_delete => 0 }, + "transaction", "Pear::LocalLoop::Schema::Result::Transaction", + "transaction_id", { cascade_delete => 0 }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/TransactionExternal.pm b/lib/Pear/LocalLoop/Schema/Result/TransactionExternal.pm index efe9fcf..80b666e 100644 --- a/lib/Pear/LocalLoop/Schema/Result/TransactionExternal.pm +++ b/lib/Pear/LocalLoop/Schema/Result/TransactionExternal.pm @@ -8,42 +8,42 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("transactions_external"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "transaction_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "external_reference_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "external_id" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - } + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "transaction_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "external_reference_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "external_id" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + } ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint([ qw/external_reference_id external_id/ ]); +__PACKAGE__->add_unique_constraint( [qw/external_reference_id external_id/] ); __PACKAGE__->belongs_to( - "transaction", - "Pear::LocalLoop::Schema::Result::Transaction", - { 'foreign.id' => 'self.transaction_id' }, + "transaction", + "Pear::LocalLoop::Schema::Result::Transaction", + { 'foreign.id' => 'self.transaction_id' }, ); __PACKAGE__->belongs_to( - "external_reference", - "Pear::LocalLoop::Schema::Result::ExternalReference", - { 'foreign.id' => 'self.external_reference_id' }, + "external_reference", + "Pear::LocalLoop::Schema::Result::ExternalReference", + { 'foreign.id' => 'self.external_reference_id' }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/TransactionMeta.pm b/lib/Pear/LocalLoop/Schema/Result/TransactionMeta.pm index 39cfd85..8dc1e37 100644 --- a/lib/Pear/LocalLoop/Schema/Result/TransactionMeta.pm +++ b/lib/Pear/LocalLoop/Schema/Result/TransactionMeta.pm @@ -8,17 +8,17 @@ use base 'DBIx::Class::Core'; __PACKAGE__->table("transactions_meta"); __PACKAGE__->add_columns( - "id" => { + "id" => { data_type => "integer", is_auto_increment => 1, is_nullable => 0, }, - "transaction_id" => { + "transaction_id" => { data_type => "integer", is_foreign_key => 1, is_nullable => 0, }, - "net_value" => { + "net_value" => { data_type => "numeric", size => [ 100, 0 ], is_nullable => 0, @@ -28,45 +28,45 @@ __PACKAGE__->add_columns( size => [ 100, 0 ], is_nullable => 0, }, - "gross_value" => { + "gross_value" => { data_type => "numeric", size => [ 100, 0 ], is_nullable => 0, }, "local_service" => { - data_type => 'boolean', - default_value => \"false", - is_nullable => 0, + data_type => 'boolean', + default_value => \"false", + is_nullable => 0, }, "regional_service" => { - data_type => 'boolean', - default_value => \"false", - is_nullable => 0, + data_type => 'boolean', + default_value => \"false", + is_nullable => 0, }, "national_service" => { - data_type => 'boolean', - default_value => \"false", - is_nullable => 0, + data_type => 'boolean', + default_value => \"false", + is_nullable => 0, }, "private_household_rebate" => { - data_type => 'boolean', - default_value => \"false", - is_nullable => 0, + data_type => 'boolean', + default_value => \"false", + is_nullable => 0, }, "business_tax_and_rebate" => { - data_type => 'boolean', - default_value => \"false", - is_nullable => 0, + data_type => 'boolean', + default_value => \"false", + is_nullable => 0, }, "stat_loc_gov" => { - data_type => 'boolean', - default_value => \"false", - is_nullable => 0, + data_type => 'boolean', + default_value => \"false", + is_nullable => 0, }, "central_loc_gov" => { - data_type => 'boolean', - default_value => \"false", - is_nullable => 0, + data_type => 'boolean', + default_value => \"false", + is_nullable => 0, }, ); diff --git a/lib/Pear/LocalLoop/Schema/Result/TransactionRecurring.pm b/lib/Pear/LocalLoop/Schema/Result/TransactionRecurring.pm index 1a766f8..2e3e987 100644 --- a/lib/Pear/LocalLoop/Schema/Result/TransactionRecurring.pm +++ b/lib/Pear/LocalLoop/Schema/Result/TransactionRecurring.pm @@ -5,88 +5,88 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components(qw/ - InflateColumn::DateTime - TimeStamp -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + TimeStamp + / +); __PACKAGE__->table("transaction_recurring"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "buyer_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "seller_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "value" => { - data_type => "numeric", - size => [ 100, 0 ], - is_nullable => 0, - }, - "start_time" => { - data_type => "datetime", - timezone => "UTC", - is_nullable => 0, - }, - "last_updated" => { - data_type => "datetime", - timezone => "UTC", - is_nullable => 1, - datetime_undef_if_invalid => 1, - }, - "essential" => { - data_type => "boolean", - default_value => \"false", - is_nullable => 0, - }, - "distance" => { - data_type => 'numeric', - size => [15], - is_nullable => 1, - }, - "category_id" => { - data_type => "integer", - is_nullable => 1, - is_foreign_key => 1, - }, - "recurring_period" => { - data_type => "varchar", - size => 255, - is_nullable => 0, - }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "buyer_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "seller_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "value" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "start_time" => { + data_type => "datetime", + timezone => "UTC", + is_nullable => 0, + }, + "last_updated" => { + data_type => "datetime", + timezone => "UTC", + is_nullable => 1, + datetime_undef_if_invalid => 1, + }, + "essential" => { + data_type => "boolean", + default_value => \"false", + is_nullable => 0, + }, + "distance" => { + data_type => 'numeric', + size => [15], + is_nullable => 1, + }, + "category_id" => { + data_type => "integer", + is_nullable => 1, + is_foreign_key => 1, + }, + "recurring_period" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "buyer", - "Pear::LocalLoop::Schema::Result::Entity", - { id => "buyer_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "buyer", + "Pear::LocalLoop::Schema::Result::Entity", + { id => "buyer_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); __PACKAGE__->belongs_to( - "seller", - "Pear::LocalLoop::Schema::Result::Entity", - { id => "seller_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "seller", + "Pear::LocalLoop::Schema::Result::Entity", + { id => "seller_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); __PACKAGE__->belongs_to( - "category", - "Pear::LocalLoop::Schema::Result::Category", - "category_id", - { cascade_delete => 0 }, + "category", "Pear::LocalLoop::Schema::Result::Category", + "category_id", { cascade_delete => 0 }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/User.pm b/lib/Pear/LocalLoop/Schema/Result/User.pm index 300d820..2e0de1b 100644 --- a/lib/Pear/LocalLoop/Schema/Result/User.pm +++ b/lib/Pear/LocalLoop/Schema/Result/User.pm @@ -7,151 +7,159 @@ use base 'DBIx::Class::Core'; use Data::UUID; -__PACKAGE__->load_components( qw/ - InflateColumn::DateTime - PassphraseColumn - TimeStamp - FilterColumn -/); +__PACKAGE__->load_components( + qw/ + InflateColumn::DateTime + PassphraseColumn + TimeStamp + FilterColumn + / +); __PACKAGE__->table("users"); __PACKAGE__->add_columns( - "id" => { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - }, - "entity_id" => { - data_type => "integer", - is_foreign_key => 1, - is_nullable => 0, - }, - "email" => { - data_type => "text", - is_nullable => 0, - }, - "join_date" => { - data_type => "datetime", - set_on_create => 1, - }, - "password" => { - data_type => "varchar", - is_nullable => 0, - size => 100, - passphrase => 'crypt', - passphrase_class => 'BlowfishCrypt', - passphrase_args => { - salt_random => 1, - cost => 8, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "entity_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "email" => { + data_type => "text", + is_nullable => 0, + }, + "join_date" => { + data_type => "datetime", + set_on_create => 1, + }, + "password" => { + data_type => "varchar", + is_nullable => 0, + size => 100, + passphrase => 'crypt', + passphrase_class => 'BlowfishCrypt', + passphrase_args => { + salt_random => 1, + cost => 8, + }, + passphrase_check_method => 'check_password', + }, + "is_admin" => { + data_type => "boolean", + default_value => \"false", + is_nullable => 0, }, - passphrase_check_method => 'check_password', - }, - "is_admin" => { - data_type => "boolean", - default_value => \"false", - is_nullable => 0, - }, ); __PACKAGE__->set_primary_key("id"); -__PACKAGE__->add_unique_constraint(["email"]); +__PACKAGE__->add_unique_constraint( ["email"] ); -__PACKAGE__->belongs_to( - "entity", - "Pear::LocalLoop::Schema::Result::Entity", - "entity_id", -); +__PACKAGE__->belongs_to( "entity", "Pear::LocalLoop::Schema::Result::Entity", + "entity_id", ); __PACKAGE__->has_many( - "session_tokens", - "Pear::LocalLoop::Schema::Result::SessionToken", - { "foreign.user_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "session_tokens", + "Pear::LocalLoop::Schema::Result::SessionToken", + { "foreign.user_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->has_many( - "device_tokens", - "Pear::LocalLoop::Schema::Result::DeviceToken", - { "foreign.user_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "device_tokens", + "Pear::LocalLoop::Schema::Result::DeviceToken", + { "foreign.user_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->has_many( - "feedback", - "Pear::LocalLoop::Schema::Result::Feedback", - { "foreign.user_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, + "feedback", + "Pear::LocalLoop::Schema::Result::Feedback", + { "foreign.user_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, ); sub sqlt_deploy_hook { - my ( $source_instance, $sqlt_table ) = @_; - my $pending_field = $sqlt_table->get_field('is_admin'); - if ( $sqlt_table->schema->translator->producer_type =~ /SQLite$/ ) { - $pending_field->{default_value} = 0; - } else { - $pending_field->{default_value} = \"false"; - } + my ( $source_instance, $sqlt_table ) = @_; + my $pending_field = $sqlt_table->get_field('is_admin'); + if ( $sqlt_table->schema->translator->producer_type =~ /SQLite$/ ) { + $pending_field->{default_value} = 0; + } + else { + $pending_field->{default_value} = \"false"; + } } -__PACKAGE__->filter_column( is_admin => { - filter_to_storage => 'to_bool', -}); +__PACKAGE__->filter_column( + is_admin => { + filter_to_storage => 'to_bool', + } +); sub to_bool { - my ( $self, $val ) = @_; - my $driver_name = $self->result_source->schema->storage->dbh->{Driver}->{Name}; - if ( $driver_name eq 'SQLite' ) { - return $val ? 1 : 0; - } else { - return $val ? 'true' : 'false'; - } + my ( $self, $val ) = @_; + my $driver_name = + $self->result_source->schema->storage->dbh->{Driver}->{Name}; + if ( $driver_name eq 'SQLite' ) { + return $val ? 1 : 0; + } + else { + return $val ? 'true' : 'false'; + } } sub generate_session { - my $self = shift; + my $self = shift; - my $token = Data::UUID->new->create_str(); - $self->create_related( - 'session_tokens', - { - token => $token, - }, - ); + my $token = Data::UUID->new->create_str(); + $self->create_related( + 'session_tokens', + { + token => $token, + }, + ); - return $token; + return $token; } sub name { - my $self = shift; - - if ( defined $self->entity->customer ) { - return $self->entity->customer->display_name; - } elsif ( defined $self->entity->organisation ) { - return $self->entity->organisation->name; - } else { - return; - } + my $self = shift; + + if ( defined $self->entity->customer ) { + return $self->entity->customer->display_name; + } + elsif ( defined $self->entity->organisation ) { + return $self->entity->organisation->name; + } + else { + return; + } } sub full_name { - my $self = shift; - - if ( defined $self->entity->customer ) { - return $self->entity->customer->full_name; - } elsif ( defined $self->entity->organisation ) { - return $self->entity->organisation->name; - } else { - return; - } + my $self = shift; + + if ( defined $self->entity->customer ) { + return $self->entity->customer->full_name; + } + elsif ( defined $self->entity->organisation ) { + return $self->entity->organisation->name; + } + else { + return; + } } # TODO Deprecate this sub? sub type { - my $self = shift; + my $self = shift; - return $self->entity->type; + return $self->entity->type; } 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategoryPg.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategoryPg.pm index 0d2739b..fdc7994 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategoryPg.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategoryPg.pm @@ -9,7 +9,8 @@ __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/ +__PACKAGE__->result_source_instance->view_definition( + qq/ SELECT "transactions"."value", "transactions"."distance", "transactions"."purchase_time", @@ -22,6 +23,7 @@ SELECT "transactions"."value", DATE_TRUNC('week', "transactions"."purchase_time") AS "quantised_weeks" FROM "transactions" 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 958ea59..b8a38f0 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategorySQLite.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategorySQLite.pm @@ -9,7 +9,8 @@ __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/ +__PACKAGE__->result_source_instance->view_definition( + qq/ SELECT "transactions"."value", "transactions"."distance", "transactions"."purchase_time", @@ -22,6 +23,7 @@ SELECT "transactions"."value", 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" -/); +/ +); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm index c710908..c94e9f7 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm @@ -9,7 +9,8 @@ __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/ +__PACKAGE__->result_source_instance->view_definition( + qq/ SELECT "value", "distance", "purchase_time", @@ -20,20 +21,21 @@ SELECT "value", DATE_TRUNC('week', "purchase_time") AS "quantised_weeks", DATE_TRUNC('month', "purchase_time") AS "quantised_months" FROM "transactions" -/); +/ +); __PACKAGE__->belongs_to( - "buyer", - "Pear::LocalLoop::Schema::Result::Entity", - { id => "buyer_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "buyer", + "Pear::LocalLoop::Schema::Result::Entity", + { id => "buyer_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); __PACKAGE__->belongs_to( - "seller", - "Pear::LocalLoop::Schema::Result::Entity", - { id => "seller_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "seller", + "Pear::LocalLoop::Schema::Result::Entity", + { id => "seller_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm index fc38ba2..027e5a7 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm @@ -9,7 +9,8 @@ __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/ +__PACKAGE__->result_source_instance->view_definition( + qq/ SELECT "value", "distance", "purchase_time", @@ -21,20 +22,21 @@ SELECT "value", DATETIME(STRFTIME('%Y-%m-%d 00:00:00',"purchase_time",'weekday 0','-6 days')) AS "quantised_weeks", DATETIME(STRFTIME('%Y-%m-00 00:00:00',"purchase_time")) AS "quantised_months" FROM "transactions" -/); +/ +); __PACKAGE__->belongs_to( - "buyer", - "Pear::LocalLoop::Schema::Result::Entity", - { id => "buyer_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "buyer", + "Pear::LocalLoop::Schema::Result::Entity", + { id => "buyer_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); __PACKAGE__->belongs_to( - "seller", - "Pear::LocalLoop::Schema::Result::Entity", - { id => "seller_id" }, - { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, + "seller", + "Pear::LocalLoop::Schema::Result::Entity", + { id => "seller_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); 1; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Category.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Category.pm index 7f05faa..0020c6c 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Category.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Category.pm @@ -6,31 +6,27 @@ use warnings; use base 'DBIx::Class::ResultSet'; sub as_hash { - my ( $self ) = @_; + my ($self) = @_; - my %category_list = ( - ( - map { - $_->id => $_->name, - } $self->all - ), - 0 => 'Uncategorised', - ); - return \%category_list; + my %category_list = ( + ( + map { $_->id => $_->name, } $self->all + ), + 0 => 'Uncategorised', + ); + return \%category_list; } sub as_hash_name_icon { - my ( $self ) = @_; + my ($self) = @_; - my %category_list = ( - ( - map { - $_->name => $_->line_icon, - } $self->all - ), - 0 => 'Uncategorised', - ); - return \%category_list; + my %category_list = ( + ( + map { $_->name => $_->line_icon, } $self->all + ), + 0 => 'Uncategorised', + ); + return \%category_list; } 1; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm index 59fd059..3fdb4e1 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm @@ -5,15 +5,17 @@ use warnings; use base 'DBIx::Class::ResultSet'; -sub sales { shift->search_related('sales', @_) } +sub sales { shift->search_related( 'sales', @_ ) } sub create_org { - my ( $self, $org ) = @_; + my ( $self, $org ) = @_; - return $self->create({ - organisation => $org, - type => 'organisation', - }); + return $self->create( + { + organisation => $org, + type => 'organisation', + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm b/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm index 2ef3e75..b7964e5 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm @@ -6,81 +6,83 @@ use warnings; use base 'DBIx::Class::ResultSet'; sub get_values { - my $self = shift; - my $id = shift; - my $include_ignored = shift; - my $include_imported = shift; + my $self = shift; + my $id = shift; + my $include_ignored = shift; + my $include_imported = shift; - return $self->find($id)->search_related( - 'values', - { - ( $include_ignored ? () : ( ignore_value => 0 ) ), - ( $include_imported ? () : ( transaction_id => undef ) ), - }, - { - order_by => { '-asc' => 'id' }, - }, - ); + return $self->find($id)->search_related( + 'values', + { + ( $include_ignored ? () : ( ignore_value => 0 ) ), + ( $include_imported ? () : ( transaction_id => undef ) ), + }, + { + order_by => { '-asc' => 'id' }, + }, + ); } sub _unordered_get_values { - my $self = shift; - my $id = shift; - my $include_ignored = shift; - my $include_imported = shift; + my $self = shift; + my $id = shift; + my $include_ignored = shift; + my $include_imported = shift; - return $self->find($id)->search_related( - 'values', - { - ( $include_ignored ? () : ( ignore_value => 0 ) ), - ( $include_imported ? () : ( transaction_id => undef ) ), - }, - ); + return $self->find($id)->search_related( + 'values', + { + ( $include_ignored ? () : ( ignore_value => 0 ) ), + ( $include_imported ? () : ( transaction_id => undef ) ), + }, + ); } sub get_users { - my $self = shift; + my $self = shift; - return $self->_unordered_get_values(@_)->search({}, - { - group_by => 'user_name', - columns => [ qw/ user_name / ], - }, - ); + return $self->_unordered_get_values(@_)->search( + {}, + { + group_by => 'user_name', + columns => [qw/ user_name /], + }, + ); } sub get_orgs { - my $self = shift; - - return $self->_unordered_get_values(@_)->search({}, - { - group_by => 'org_name', - columns => [ qw/ org_name / ], - }, - ); + my $self = shift; + + return $self->_unordered_get_values(@_)->search( + {}, + { + group_by => 'org_name', + columns => [qw/ org_name /], + }, + ); } sub get_lookups { - my $self = shift; - my $id = shift; + my $self = shift; + my $id = shift; - my $lookup_rs = $self->find($id)->search_related( - 'lookups', - undef, - { - prefetch => { entity => [ qw/ organisation customer / ] }, - order_by => { '-asc' => 'me.id' }, - }, - ); - my $lookup_map = { - map { - $_->name => { - entity_id => $_->entity->id, - name => $_->entity->name, - }, - } $lookup_rs->all - }; - return $lookup_map; + my $lookup_rs = $self->find($id)->search_related( + 'lookups', + undef, + { + prefetch => { entity => [qw/ organisation customer /] }, + order_by => { '-asc' => 'me.id' }, + }, + ); + my $lookup_map = { + map { + $_->name => { + entity_id => $_->entity->id, + name => $_->entity->name, + }, + } $lookup_rs->all + }; + return $lookup_map; } 1; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm index 5c94898..2a1dedc 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm @@ -8,87 +8,103 @@ use base 'DBIx::Class::ResultSet'; use DateTime; sub get_latest { - my $self = shift; - my $type = shift; + my $self = shift; + my $type = shift; - my $type_result = $self->find_by_type( $type ); + my $type_result = $self->find_by_type($type); - return unless defined $type_result; + return unless defined $type_result; - my $latest = $type_result->search_related('sets', {}, { - order_by => { -desc => 'date' }, - })->first; + my $latest = $type_result->search_related( + 'sets', + {}, + { + order_by => { -desc => 'date' }, + } + )->first; - return $latest; + return $latest; } sub create_new { - my $self = shift; - my $type = shift; - my $date = shift; + my $self = shift; + my $type = shift; + my $date = shift; - my $type_result = $self->find_by_type($type); + my $type_result = $self->find_by_type($type); - return unless $type_result; + return unless $type_result; - return $type_result->create_new($date); + return $type_result->create_new($date); } sub find_by_type { - my $self = shift; - my $type = shift; + my $self = shift; + my $type = shift; - return $self->find({ type => $type }); + return $self->find( { type => $type } ); } sub recalculate_all { - my $self = shift; - - for my $leaderboard_result ( $self->all ) { - my $lb_type = $leaderboard_result->type; - if ( $lb_type =~ /^daily/ ) { - - # Recalculating a daily set. This is calculated from the start of the - # day, so we need yesterdays date: - my $date = DateTime->today->subtract( days => 1 ); - $self->_recalculate_leaderboard( $leaderboard_result, $date, 'days' ); - - } elsif ( $lb_type =~ /^weekly/ ) { - - # Recalculating a weekly set. This is calculated from a Monday, of the - # week before. - my $date = DateTime->today->truncate( to => 'week' )->subtract( weeks => 1 ); - $self->_recalculate_leaderboard( $leaderboard_result, $date, 'weeks' ); - - } elsif ( $lb_type =~ /^monthly/ ) { - - # Recalculate a monthly set. This is calculated from the first of the - # month, for the month before. - my $date = DateTime->today->truncate( to => 'month' )->subtract( months => 1); - $self->_recalculate_leaderboard( $leaderboard_result, $date, 'months' ); - - } elsif ( $lb_type =~ /^all_time/ ) { - - # Recalculate for an all time set. This is calculated similarly to - # daily, but is calculated from an end time. - my $date = DateTime->today; - $self->_recalculate_leaderboard( $leaderboard_result, $date, 'days' ); - - } else { - warn "Unrecognised Set"; + my $self = shift; + + for my $leaderboard_result ( $self->all ) { + my $lb_type = $leaderboard_result->type; + if ( $lb_type =~ /^daily/ ) { + + # Recalculating a daily set. This is calculated from the start of the + # day, so we need yesterdays date: + my $date = DateTime->today->subtract( days => 1 ); + $self->_recalculate_leaderboard( $leaderboard_result, $date, + 'days' ); + + } + elsif ( $lb_type =~ /^weekly/ ) { + + # Recalculating a weekly set. This is calculated from a Monday, of the + # week before. + my $date = + DateTime->today->truncate( to => 'week' )->subtract( weeks => 1 ); + $self->_recalculate_leaderboard( $leaderboard_result, $date, + 'weeks' ); + + } + elsif ( $lb_type =~ /^monthly/ ) { + + # Recalculate a monthly set. This is calculated from the first of the + # month, for the month before. + my $date = DateTime->today->truncate( to => 'month' ) + ->subtract( months => 1 ); + $self->_recalculate_leaderboard( $leaderboard_result, $date, + 'months' ); + + } + elsif ( $lb_type =~ /^all_time/ ) { + + # Recalculate for an all time set. This is calculated similarly to + # daily, but is calculated from an end time. + my $date = DateTime->today; + $self->_recalculate_leaderboard( $leaderboard_result, $date, + 'days' ); + + } + else { + warn "Unrecognised Set"; + } } - } } sub _recalculate_leaderboard { - my ( $self, $lb_result, $date, $diff ) = @_; - - $self->result_source->schema->txn_do( sub { - $lb_result->sets->related_resultset('values')->delete_all; - $lb_result->sets->delete_all; - $lb_result->create_new($date->clone->subtract( $diff => 1 )); - $lb_result->create_new($date); - }); + my ( $self, $lb_result, $date, $diff ) = @_; + + $self->result_source->schema->txn_do( + sub { + $lb_result->sets->related_resultset('values')->delete_all; + $lb_result->sets->delete_all; + $lb_result->create_new( $date->clone->subtract( $diff => 1 ) ); + $lb_result->create_new($date); + } + ); } 1; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm index 10560b2..db6ad56 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm @@ -5,6 +5,6 @@ use warnings; use base 'DBIx::Class::ResultSet'; -sub entity { shift->search_related('entity', @_) } +sub entity { shift->search_related( 'entity', @_ ) } 1; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Transaction.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Transaction.pm index 822abf2..7ab84d6 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Transaction.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Transaction.pm @@ -8,47 +8,51 @@ use base 'DBIx::Class::ResultSet'; use DateTime; sub search_between { - my ( $self, $from, $to ) = @_; - - my $dtf = $self->result_source->schema->storage->datetime_parser; - return $self->search({ - purchase_time => { - -between => [ - $dtf->format_datetime($from), - $dtf->format_datetime($to), - ], - }, - }); + my ( $self, $from, $to ) = @_; + + my $dtf = $self->result_source->schema->storage->datetime_parser; + return $self->search( + { + purchase_time => { + -between => + [ $dtf->format_datetime($from), $dtf->format_datetime($to), ], + }, + } + ); } sub search_before { - my ( $self, $date ) = @_; - - my $dtf = $self->result_source->schema->storage->datetime_parser; - return $self->search({ - purchase_time => { '<' => $dtf->format_datetime( $date ) }, - }); + my ( $self, $date ) = @_; + + my $dtf = $self->result_source->schema->storage->datetime_parser; + return $self->search( + { + purchase_time => { '<' => $dtf->format_datetime($date) }, + } + ); } sub today_rs { - my ( $self ) = @_; + my ($self) = @_; - my $today = DateTime->today(); - return $self->search_between( $today, $today->clone->add( days => 1 ) ); + my $today = DateTime->today(); + return $self->search_between( $today, $today->clone->add( days => 1 ) ); } sub week_rs { - my ( $self ) = @_; + my ($self) = @_; - my $today = DateTime->today(); - return $self->search_between( $today->clone->subtract( days => 7 ), $today ); + my $today = DateTime->today(); + return $self->search_between( $today->clone->subtract( days => 7 ), + $today ); } sub month_rs { - my ( $self ) = @_; + my ($self) = @_; - my $today = DateTime->today(); - return $self->search_between( $today->clone->subtract( days => 30 ), $today ); + my $today = DateTime->today(); + return $self->search_between( $today->clone->subtract( days => 30 ), + $today ); } 1; diff --git a/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm b/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm index 9372a9f..9f5b841 100644 --- a/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm +++ b/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm @@ -37,11 +37,11 @@ This option is then provided to the Schema's 'connect' function. =cut option connection => ( - is => 'ro', - format => 's', - required => 0, - short => 'c', - doc => "The DBI connection string to use", + is => 'ro', + format => 's', + required => 0, + short => 'c', + doc => "The DBI connection string to use", ); =head2 --username ( -u ) @@ -51,11 +51,11 @@ The username to use for connection to the database =cut option username => ( - is => 'ro', - format => 's', - default => '', - short => 'u', - doc => "The username for the DB connection", + is => 'ro', + format => 's', + default => '', + short => 'u', + doc => "The username for the DB connection", ); =head2 --password ( -p ) @@ -65,11 +65,11 @@ The password to use for connection to the database =cut option password => ( - is => 'ro', - format => 's', - default => '', - short => 'p', - doc => "The password for the supplied user", + is => 'ro', + format => 's', + default => '', + short => 'p', + doc => "The password for the supplied user", ); =head2 --force ( -f ) @@ -80,10 +80,10 @@ the same version of ddl items. =cut option force => ( - is => 'ro', - default => sub { 0 }, - short => 'f', - doc => "Force the action if required", + is => 'ro', + default => sub { 0 }, + short => 'f', + doc => "Force the action if required", ); =head2 --version ( -v ) @@ -94,11 +94,11 @@ ddl. =cut option version => ( - is => 'ro', - format => 'i', - default => sub { shift->dh->schema->schema_version }, - short => 'v', - doc => "Version to use as target", + is => 'ro', + format => 'i', + default => sub { shift->dh->schema->schema_version }, + short => 'v', + doc => "Version to use as target", ); =head1 ATTRIBUTES @@ -113,8 +113,8 @@ to be defined in the 'new_with_options' call. =cut has schema_class => ( - is => 'ro', - required => 1, + is => 'ro', + required => 1, ); =head2 schema @@ -125,15 +125,12 @@ This is the connected schema. This uses the 'schema_class' attribute and =cut has schema => ( - is => 'lazy', - builder => sub { - my $self = shift; - return use_module( $self->schema_class )->connect( - $self->connection, - $self->username, - $self->password, - ); - }, + is => 'lazy', + builder => sub { + my $self = shift; + return use_module( $self->schema_class ) + ->connect( $self->connection, $self->username, $self->password, ); + }, ); =head2 script_directory @@ -144,8 +141,8 @@ versions. Defaults to 'share/ddl'. =cut has script_directory => ( - is => 'ro', - default => 'share/ddl', + is => 'ro', + default => 'share/ddl', ); =head2 databases @@ -160,8 +157,8 @@ defaults to returning the following: =cut has databases => ( - is => 'ro', - default => sub { [ qw/ PostgreSQL SQLite / ] }, + is => 'ro', + default => sub { [qw/ PostgreSQL SQLite /] }, ); =head2 dh @@ -172,16 +169,18 @@ This returns the actual DeploymentHandler, set up using the 'schema', =cut has dh => ( - is => 'lazy', - builder => sub { - my ( $self ) = @_; - return DBIx::Class::DeploymentHandler->new({ - schema => $self->schema, - force_overwrite => $self->force, - script_directory => $self->script_directory, - databases => $self->databases, - }); - } + is => 'lazy', + builder => sub { + my ($self) = @_; + return DBIx::Class::DeploymentHandler->new( + { + schema => $self->schema, + force_overwrite => $self->force, + script_directory => $self->script_directory, + databases => $self->databases, + } + ); + } ); =head1 COMMANDS @@ -195,17 +194,19 @@ This will create the ddl files required to perform an upgrade. =cut sub cmd_write_ddl { - my ( $self ) = @_; - - $self->dh->prepare_install; - my $v = $self->version; - - if ( $v > 1 ) { - $self->dh->prepare_upgrade({ - from_version => $v - 1, - to_version => $v, - }); - } + my ($self) = @_; + + $self->dh->prepare_install; + my $v = $self->version; + + if ( $v > 1 ) { + $self->dh->prepare_upgrade( + { + from_version => $v - 1, + to_version => $v, + } + ); + } } =head2 install_dh @@ -216,12 +217,14 @@ database. Only for use on a pre-existing database. =cut sub cmd_install_dh { - my ( $self ) = @_; + my ($self) = @_; - $self->dh->install_version_storage; - $self->dh->add_database_version({ - version => $self->version, - }); + $self->dh->install_version_storage; + $self->dh->add_database_version( + { + version => $self->version, + } + ); } =head2 install @@ -231,11 +234,13 @@ This command will install all the tables to the provided database =cut sub cmd_install { - my ( $self ) = @_; + my ($self) = @_; - $self->dh->install({ - version => $self->version, - }); + $self->dh->install( + { + version => $self->version, + } + ); } =head2 upgrade @@ -245,9 +250,9 @@ This command will upgrade all tables to the latest versions =cut sub cmd_upgrade { - my ( $self ) = @_; + my ($self) = @_; - $self->dh->upgrade; + $self->dh->upgrade; } =head1 AUTHOR diff --git a/lib/Test/Pear/LocalLoop.pm b/lib/Test/Pear/LocalLoop.pm index deffc44..5da847c 100644 --- a/lib/Test/Pear/LocalLoop.pm +++ b/lib/Test/Pear/LocalLoop.pm @@ -9,44 +9,45 @@ use DBIx::Class::Fixtures; # Conditionally require Test::PostgreSQL sub BUILD { - if ( $ENV{PEAR_TEST_PG} ) { - require Test::PostgreSQL - or die "you need Test::PostgreSQL to run PG testing"; - Test::PostgreSQL->import; - } + if ( $ENV{PEAR_TEST_PG} ) { + require Test::PostgreSQL + or die "you need Test::PostgreSQL to run PG testing"; + Test::PostgreSQL->import; + } } sub DEMOLISH { - my ( $self, $in_global_destruction ) = @_; + my ( $self, $in_global_destruction ) = @_; - if ( $ENV{PEAR_TEST_PG} && !$in_global_destruction ) { - $self->mojo->app->schema->storage->dbh->disconnect; - $self->pg->stop; - } + if ( $ENV{PEAR_TEST_PG} && !$in_global_destruction ) { + $self->mojo->app->schema->storage->dbh->disconnect; + $self->pg->stop; + } } has pg => ( - is => 'lazy', - builder => sub { - return Test::PostgreSQL->new(); - }, + is => 'lazy', + builder => sub { + return Test::PostgreSQL->new(); + }, ); has config => ( - is => 'lazy', - builder => sub { - my $self = shift; - my $file = File::Temp->new; + is => 'lazy', + builder => sub { + my $self = shift; + my $file = File::Temp->new; - my $dsn; + my $dsn; - if ( $ENV{PEAR_TEST_PG} ) { - $dsn = $self->pg->dsn; - } else { - $dsn = "dbi:SQLite::memory:"; - } + if ( $ENV{PEAR_TEST_PG} ) { + $dsn = $self->pg->dsn; + } + else { + $dsn = "dbi:SQLite::memory:"; + } - print $file <<"END"; + print $file <<"END"; { dsn => "$dsn", user => undef, @@ -54,159 +55,172 @@ has config => ( } END - $file->seek( 0, SEEK_END ); - return $file; - }, + $file->seek( 0, SEEK_END ); + return $file; + }, ); has mojo => ( - is => 'lazy', - builder => sub { - my $self = shift; + is => 'lazy', + builder => sub { + my $self = shift; - $ENV{MOJO_CONFIG} = $self->config->filename; + $ENV{MOJO_CONFIG} = $self->config->filename; - my $t = Test::Mojo->new('Pear::LocalLoop'); - $t->app->schema->deploy; + my $t = Test::Mojo->new('Pear::LocalLoop'); + $t->app->schema->deploy; - return $t; - }, + return $t; + }, ); has etc_dir => ( - is => 'lazy', - builder => sub { die "etc dir not set" }, + is => 'lazy', + builder => sub { die "etc dir not set" }, ); has _deployed => ( - is => 'rwp', - default => 0, + is => 'rwp', + default => 0, ); sub framework { - my $self = shift; - my $no_populate = shift; - - my $t = $self->mojo; - my $schema = $t->app->schema; - - unless ( $no_populate || $self->_deployed ) { - $schema->resultset('Leaderboard')->populate([ - [ qw/ name type / ], - [ 'Daily Total', 'daily_total' ], - [ 'Daily Count', 'daily_count' ], - [ 'Weekly Total', 'weekly_total' ], - [ 'Weekly Count', 'weekly_count' ], - [ 'Monthly Total', 'monthly_total' ], - [ 'Monthly Count', 'monthly_count' ], - [ 'All Time Total', 'all_time_total' ], - [ 'All Time Count', 'all_time_count' ], - ]); - } - - $self->_set__deployed(1); - - return $t; -}; + my $self = shift; + my $no_populate = shift; + + my $t = $self->mojo; + my $schema = $t->app->schema; + + unless ( $no_populate || $self->_deployed ) { + $schema->resultset('Leaderboard')->populate( + [ + [qw/ name type /], + [ 'Daily Total', 'daily_total' ], + [ 'Daily Count', 'daily_count' ], + [ 'Weekly Total', 'weekly_total' ], + [ 'Weekly Count', 'weekly_count' ], + [ 'Monthly Total', 'monthly_total' ], + [ 'Monthly Count', 'monthly_count' ], + [ 'All Time Total', 'all_time_total' ], + [ 'All Time Count', 'all_time_count' ], + ] + ); + } + + $self->_set__deployed(1); + + return $t; +} sub dump_error { - return sub { - 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; - } - }; + return sub { + 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; + } + }; } sub register_customer { - my $self = shift; - my $args = shift; + my $self = shift; + my $args = shift; - my $json = { - usertype => 'customer', - %$args, - }; + my $json = { + usertype => 'customer', + %$args, + }; - $self->framework->post_ok('/api/register' => json => $json) - ->status_is(200)->or($self->dump_error) - ->json_is('/success', Mojo::JSON->true)->or($self->dump_error); + $self->framework->post_ok( '/api/register' => json => $json ) + ->status_is(200)->or( $self->dump_error ) + ->json_is( '/success', Mojo::JSON->true )->or( $self->dump_error ); } sub register_organisation { - my ( $self, $args ) = @_; + my ( $self, $args ) = @_; - $args->{usertype} = 'organisation'; + $args->{usertype} = 'organisation'; - $self->framework->post_ok('/api/register' => json => $args) - ->status_is(200)->or($self->dump_error) - ->json_is('/success', Mojo::JSON->true)->or($self->dump_error); + $self->framework->post_ok( '/api/register' => json => $args ) + ->status_is(200)->or( $self->dump_error ) + ->json_is( '/success', Mojo::JSON->true )->or( $self->dump_error ); } sub login { - my $self = shift; - my $args = shift; + my $self = shift; + my $args = shift; - $self->framework->post_ok('/api/login' => json => $args) - ->status_is(200)->or($self->dump_error) - ->json_is('/success', Mojo::JSON->true)->or($self->dump_error); + $self->framework->post_ok( '/api/login' => json => $args )->status_is(200) + ->or( $self->dump_error )->json_is( '/success', Mojo::JSON->true ) + ->or( $self->dump_error ); - return $self->framework->tx->res->json->{session_key}; + return $self->framework->tx->res->json->{session_key}; } sub logout { - my $self = shift; - my $session_key = shift; + my $self = shift; + my $session_key = shift; - $self->framework->post_ok('/api/logout' => json => { session_key => $session_key }) - ->status_is(200) - ->json_is('/success', Mojo::JSON->true) - ->json_like('/message', qr/Logged Out/); + $self->framework->post_ok( + '/api/logout' => json => { session_key => $session_key } ) + ->status_is(200)->json_is( '/success', Mojo::JSON->true ) + ->json_like( '/message', qr/Logged Out/ ); } sub gen_upload { - my ( $self, $args ) = @_; - - my $file = { - content => '', - filename => 'text.jpg', - 'Content-Type' => 'image/jpeg', - }; - - return { - json => Mojo::JSON::encode_json($args), - file => $file, - }; + my ( $self, $args ) = @_; + + my $file = { + content => '', + filename => 'text.jpg', + 'Content-Type' => 'image/jpeg', + }; + + return { + json => Mojo::JSON::encode_json($args), + file => $file, + }; } sub install_fixtures { - my ( $self, $fixture_name ) = @_; - - my $fixtures = DBIx::Class::Fixtures->new({ - config_dir => File::Spec->catdir( $self->etc_dir, 'fixtures', 'config'), - }); - - my $t = $self->framework(1); - my $schema = $t->app->schema; - - $fixtures->populate({ - directory => File::Spec->catdir( $self->etc_dir, 'fixtures', 'data', $fixture_name ), - no_deploy => 1, - schema => $schema, - }); - - # Reset table id sequences - if ( $ENV{PEAR_TEST_PG} ) { - $schema->storage->dbh_do( - sub { - my ( $storage, $dbh, $sets ) = @_; - for my $table ( keys %$sets ) { - my $seq = $sets->{$table}; - $dbh->do( - qq/ + my ( $self, $fixture_name ) = @_; + + my $fixtures = DBIx::Class::Fixtures->new( + { + config_dir => + File::Spec->catdir( $self->etc_dir, 'fixtures', 'config' ), + } + ); + + my $t = $self->framework(1); + my $schema = $t->app->schema; + + $fixtures->populate( + { + directory => File::Spec->catdir( + $self->etc_dir, 'fixtures', 'data', $fixture_name + ), + no_deploy => 1, + schema => $schema, + } + ); + + # Reset table id sequences + if ( $ENV{PEAR_TEST_PG} ) { + $schema->storage->dbh_do( + sub { + my ( $storage, $dbh, $sets ) = @_; + for my $table ( keys %$sets ) { + my $seq = $sets->{$table}; + $dbh->do( + qq/ SELECT setval( '$seq', COALESCE( @@ -215,17 +229,18 @@ sub install_fixtures { ), false ); - /); - } - }, - { - entities => 'entities_id_seq', - organisations => 'organisations_id_seq', - users => 'users_id_seq', - customers => 'customers_id_seq', - } - ); - } + / + ); + } + }, + { + entities => 'entities_id_seq', + organisations => 'organisations_id_seq', + users => 'users_id_seq', + customers => 'customers_id_seq', + } + ); + } } 1; From ee7fe2c7b47304f5e7600974a2e99d3ee6a3239a Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 13:22:29 +0000 Subject: [PATCH 268/289] Update readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7bcca11..75e4256 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,8 @@ Test files are found in the `t/` directory. ## Code Formatting Run `for f in ./lib/**/*.pm; do perltidy -b $f; done` to format all Perl files -with [Perl-Tidy](https://metacpan.org/release/Perl-Tidy). +with [Perl-Tidy](https://metacpan.org/release/Perl-Tidy) (there is no built-in +option to format files recursively). Run `perlcritic lib` to lint all Perl files with [Perl-Critic](https://metacpan.org/release/Perl-Critic). From c5c074903da3334bdb13d61314c88d1c1f48674d Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 15:02:00 +0000 Subject: [PATCH 269/289] Add explicit `return`s --- lib/Pear/LocalLoop/Command/codepoint_open.pm | 2 ++ lib/Pear/LocalLoop/Command/dev_data.pm | 2 ++ lib/Pear/LocalLoop/Command/dev_transactions.pm | 2 ++ lib/Pear/LocalLoop/Command/latlong_setup.pm | 4 ++++ lib/Pear/LocalLoop/Command/leaderboard.pm | 2 ++ .../LocalLoop/Command/recalc_leaderboards.pm | 2 ++ lib/Pear/LocalLoop/Command/recur_transactions.pm | 2 ++ lib/Pear/LocalLoop/Controller/Admin.pm | 6 ++++++ .../LocalLoop/Controller/Admin/Categories.pm | 10 ++++++++++ lib/Pear/LocalLoop/Controller/Admin/Feedback.pm | 6 ++++++ lib/Pear/LocalLoop/Controller/Admin/Import.pm | 14 ++++++++++++++ .../LocalLoop/Controller/Admin/ImportFrom.pm | 4 ++++ .../LocalLoop/Controller/Admin/Organisations.pm | 16 ++++++++++++++++ lib/Pear/LocalLoop/Controller/Admin/Reports.pm | 2 ++ lib/Pear/LocalLoop/Controller/Admin/Tokens.pm | 10 ++++++++++ .../LocalLoop/Controller/Admin/Transactions.pm | 8 ++++++++ lib/Pear/LocalLoop/Controller/Admin/Users.pm | 6 ++++++ lib/Pear/LocalLoop/Controller/Api/Auth.pm | 2 ++ .../Controller/Api/V1/Supplier/Location.pm | 4 ++++ lib/Pear/LocalLoop/Controller/Root.pm | 8 ++++++++ lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm | 4 ++++ lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm | 4 ++++ lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm | 4 ++++ lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm | 3 ++- lib/Pear/LocalLoop/Plugin/Currency.pm | 2 ++ lib/Pear/LocalLoop/Plugin/Datetime.pm | 1 + lib/Pear/LocalLoop/Plugin/Minion.pm | 3 ++- .../Plugin/Minion/Job/csv_postcode_import.pm | 2 ++ .../Plugin/Minion/Job/csv_supplier_import.pm | 2 ++ .../Plugin/Minion/Job/csv_transaction_import.pm | 2 ++ .../Plugin/Minion/Job/entity_postcode_lookup.pm | 2 ++ .../Plugin/Minion/Job/leaderboards_recalc.pm | 2 ++ lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm | 2 ++ lib/Pear/LocalLoop/Plugin/Postcodes.pm | 2 ++ lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm | 3 ++- lib/Pear/LocalLoop/Plugin/Validators.pm | 2 ++ lib/Pear/LocalLoop/Schema/Result/Organisation.pm | 2 ++ lib/Pear/LocalLoop/Schema/Result/Transaction.pm | 2 ++ lib/Pear/LocalLoop/Schema/Result/User.pm | 14 ++++++++------ lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm | 4 +++- .../LocalLoop/Schema/ResultSet/Leaderboard.pm | 4 ++++ .../LocalLoop/Schema/ResultSet/Organisation.pm | 2 +- .../LocalLoop/Schema/Script/DeploymentHandler.pm | 8 ++++++++ lib/Test/Pear/LocalLoop.pm | 14 ++++++++++++++ 44 files changed, 191 insertions(+), 11 deletions(-) diff --git a/lib/Pear/LocalLoop/Command/codepoint_open.pm b/lib/Pear/LocalLoop/Command/codepoint_open.pm index 9daee08..b4570b4 100644 --- a/lib/Pear/LocalLoop/Command/codepoint_open.pm +++ b/lib/Pear/LocalLoop/Command/codepoint_open.pm @@ -55,6 +55,8 @@ sub run { { key => 'primary' }, ); } + + return 1; } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Command/dev_data.pm b/lib/Pear/LocalLoop/Command/dev_data.pm index 611dcb5..c230c4a 100644 --- a/lib/Pear/LocalLoop/Command/dev_data.pm +++ b/lib/Pear/LocalLoop/Command/dev_data.pm @@ -90,6 +90,8 @@ sub run { }, } ); + + return 1; } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Command/dev_transactions.pm b/lib/Pear/LocalLoop/Command/dev_transactions.pm index 2c491e0..adcdf51 100644 --- a/lib/Pear/LocalLoop/Command/dev_transactions.pm +++ b/lib/Pear/LocalLoop/Command/dev_transactions.pm @@ -90,6 +90,8 @@ sub run { } } } + + return 1; } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Command/latlong_setup.pm b/lib/Pear/LocalLoop/Command/latlong_setup.pm index 4a3d649..9c34136 100644 --- a/lib/Pear/LocalLoop/Command/latlong_setup.pm +++ b/lib/Pear/LocalLoop/Command/latlong_setup.pm @@ -29,6 +29,8 @@ sub run { ); $result->update( { distance => $distance } ) if defined $distance; } + + return 1; } sub _set_lat_long_for_result { @@ -53,6 +55,8 @@ sub _set_lat_long_for_result { ); } } + + return 1; } sub _calculate_distance { diff --git a/lib/Pear/LocalLoop/Command/leaderboard.pm b/lib/Pear/LocalLoop/Command/leaderboard.pm index 064b322..bd5df60 100644 --- a/lib/Pear/LocalLoop/Command/leaderboard.pm +++ b/lib/Pear/LocalLoop/Command/leaderboard.pm @@ -71,6 +71,8 @@ sub run { } } } + + return 1; } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm b/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm index b04514e..5ea8fa5 100644 --- a/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm +++ b/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm @@ -13,6 +13,8 @@ sub run { my $leaderboard_rs = $self->app->schema->resultset('Leaderboard'); $leaderboard_rs->recalculate_all; + + return 1; } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Command/recur_transactions.pm b/lib/Pear/LocalLoop/Command/recur_transactions.pm index 35fa032..58bf927 100644 --- a/lib/Pear/LocalLoop/Command/recur_transactions.pm +++ b/lib/Pear/LocalLoop/Command/recur_transactions.pm @@ -153,6 +153,8 @@ sub run { $recur_result->update( { last_updated => $purchase_time } ); } + + return 1; } =head1 SYNOPSIS diff --git a/lib/Pear/LocalLoop/Controller/Admin.pm b/lib/Pear/LocalLoop/Controller/Admin.pm index 13b2d73..01049d3 100644 --- a/lib/Pear/LocalLoop/Controller/Admin.pm +++ b/lib/Pear/LocalLoop/Controller/Admin.pm @@ -34,6 +34,8 @@ sub home { pending => $pending_feedback_rs->count, }, ); + + return 1; } sub auth_login { @@ -52,6 +54,8 @@ sub auth_login { . "]" ); $c->redirect_to('/admin'); } + + return 1; } sub auth_logout { @@ -59,6 +63,8 @@ sub auth_logout { $c->logout; $c->redirect_to('/admin'); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Categories.pm b/lib/Pear/LocalLoop/Controller/Admin/Categories.pm index 6f89b3c..53a3698 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Categories.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Categories.pm @@ -12,6 +12,8 @@ sub index { my $category_rs = $c->result_set; $category_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); $c->stash( categories => [ $category_rs->all ] ); + + return 1; } # POST @@ -43,6 +45,8 @@ sub create { $c->result_set->create( { name => $category_name } ); } $c->redirect_to('/admin/categories'); + + return 1; } # GET @@ -58,6 +62,8 @@ sub read { $c->flash( error => 'No Category found' ); $c->redirect_to('/admin/categories'); } + + return 1; } # POST @@ -95,6 +101,8 @@ sub update { $c->flash( error => 'No Category found' ); $c->redirect_to('/admin/categories'); } + + return 1; } # DELETE @@ -112,6 +120,8 @@ sub delete { $c->flash( error => 'No Category found' ); } $c->redirect_to('/admin/categories'); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm b/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm index 9a7188b..048f2af 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm @@ -18,6 +18,8 @@ sub index { }, ); $c->stash( feedback_rs => $feedback_rs ); + + return 1; } sub read { @@ -32,6 +34,8 @@ sub read { $c->flash( error => 'No Feedback found' ); $c->redirect_to('/admin/feedback'); } + + return 1; } sub actioned { @@ -48,6 +52,8 @@ sub actioned { $c->flash( error => 'No Feedback found' ); $c->redirect_to('/admin/feedback'); } + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Import.pm b/lib/Pear/LocalLoop/Controller/Admin/Import.pm index 8ca2e8a..4d1b0ee 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Import.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Import.pm @@ -21,6 +21,8 @@ sub index { }, ); $c->stash( import_rs => $import_rs ); + + return 1; } sub list { @@ -46,10 +48,14 @@ sub list { import_org_rs => $import_org_rs, import_lookup_rs => $import_lookup_rs, ); + + return 1; } sub get_add { my $c = shift; + + return 1; } sub post_add { @@ -147,6 +153,8 @@ sub post_add { $c->flash( success => 'Created Value Set' ); $c->redirect_to( '/admin/import/' . $value_set->id ); + + return 1; } sub _csv_flash_error { @@ -160,6 +168,8 @@ sub _csv_flash_error { #csv_data => $c->param('csv'), date_format => $c->param('date_format'), ); + + return 1; } sub get_user { @@ -209,6 +219,8 @@ sub get_user { lookup => $lookup_result, user_name => $user_name, ); + + return 1; } sub get_org { @@ -258,6 +270,8 @@ sub get_org { lookup => $lookup_result, org_name => $org_name, ); + + return 1; } sub ignore_value { diff --git a/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm b/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm index 72ce999..e8b47af 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm @@ -15,6 +15,8 @@ sub index { ]; $c->app->max_request_size(104857600); + + return 1; } sub post_suppliers { @@ -130,6 +132,8 @@ sub org_search { ); $c->render( json => \@results ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index ef85636..5b05a42 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -21,10 +21,14 @@ sub list { ); $c->stash( orgs_rs => $orgs_rs, ); + + return 1; } sub add_org { my $c = shift; + + return 1; } sub add_org_submit { @@ -87,6 +91,8 @@ sub add_org_submit { $c->redirect_to( '/admin/organisations/' . $organisation->id ); } }; + + return 1; } sub valid_read { @@ -112,6 +118,8 @@ sub valid_read { transactions => $transactions, associations => $assoc, ); + + return 1; } sub valid_edit { @@ -183,6 +191,8 @@ sub valid_edit { } }; $c->redirect_to( '/admin/organisations/' . $c->param('id') ); + + return 1; } sub merge_list { @@ -212,6 +222,8 @@ sub merge_list { org_result => $org_result, org_rs => $org_rs, ); + + return 1; } sub merge_detail { @@ -239,6 +251,8 @@ sub merge_detail { org_result => $org_result, target_result => $target_result, ); + + return 1; } sub merge_confirm { @@ -295,6 +309,8 @@ sub merge_confirm { } $c->redirect_to( '/admin/organisations/' . $org_id . '/merge/' . $target_id ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm index fece5ee..8040fdf 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm @@ -59,6 +59,8 @@ sub transaction_data { json => { json => { data => $transaction_data } }, html => { transaction_rs => encode_json($transaction_data) }, ); + + return 1; } sub pg_or_sqlite { diff --git a/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm b/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm index 67481c5..887f2a8 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm @@ -12,6 +12,8 @@ sub index { my $token_rs = $c->result_set; $token_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); $c->stash( tokens => [ $token_rs->all ] ); + + return 1; } # POST @@ -43,6 +45,8 @@ sub create { $c->result_set->create( { name => $token_name } ); } $c->redirect_to('/admin/tokens'); + + return 1; } # GET @@ -58,6 +62,8 @@ sub read { $c->flash( error => 'No Token found' ); $c->redirect_to('/admin/tokens'); } + + return 1; } # POST @@ -89,6 +95,8 @@ sub update { $c->flash( error => 'No Token found' ); $c->redirect_to('/admin/tokens'); } + + return 1; } # DELETE @@ -105,6 +113,8 @@ sub delete { $c->flash( error => 'No Token found' ); } $c->redirect_to('/admin/tokens'); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm index f9cf3ee..a1833a4 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm @@ -66,6 +66,8 @@ sub index { count => $count, }, ); + + return 1; } sub read { @@ -80,6 +82,8 @@ sub read { $c->flash( error => 'No transaction found' ); $c->redirect_to('/admin/transactions'); } + + return 1; } sub image { @@ -95,6 +99,8 @@ sub image { else { $c->reply->static('image/no_transaction.jpg'); } + + return 1; } sub delete { @@ -114,6 +120,8 @@ sub delete { $c->flash( error => 'No transaction found' ); $c->redirect_to('/admin/transactions'); } + + return 1; } sub pg_or_sqlite { diff --git a/lib/Pear/LocalLoop/Controller/Admin/Users.pm b/lib/Pear/LocalLoop/Controller/Admin/Users.pm index a808a06..f5a2126 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Users.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Users.pm @@ -32,6 +32,8 @@ sub index { } ); $c->stash( user_rs => $user_rs ); + + return 1; } sub read { @@ -57,6 +59,8 @@ sub read { $c->flash( error => 'No User found' ); $c->redirect_to('/admin/users'); } + + return 1; } sub update { @@ -189,6 +193,8 @@ sub update { } $c->redirect_to( '/admin/users/' . $id ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/Auth.pm b/lib/Pear/LocalLoop/Controller/Api/Auth.pm index cb03903..64ca702 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Auth.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Auth.pm @@ -139,6 +139,8 @@ sub post_logout { message => 'Logged Out', } ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm index 6199372..3fec296 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm @@ -122,6 +122,8 @@ sub index { } }, ); + + return 1; } sub trail_load { @@ -204,6 +206,8 @@ sub trail_load { } }, ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Controller/Root.pm b/lib/Pear/LocalLoop/Controller/Root.pm index 28a089e..6ed1bb9 100644 --- a/lib/Pear/LocalLoop/Controller/Root.pm +++ b/lib/Pear/LocalLoop/Controller/Root.pm @@ -7,6 +7,8 @@ sub index { # if ( $c->is_user_authenticated ) { # $c->redirect_to('/home'); # } + + return 1; } sub under { @@ -28,6 +30,8 @@ sub auth_login { else { $c->redirect_to('/'); } + + return 1; } sub auth_logout { @@ -35,10 +39,14 @@ sub auth_logout { $c->logout; $c->redirect_to('/'); + + return 1; } sub home { my $c = shift; + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm index 164e484..e44be58 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm @@ -24,6 +24,8 @@ sub import_csv { while ( my $row = $self->get_csv_line ) { $self->_row_to_result($row); } + + return 1; } sub _row_to_result { @@ -45,6 +47,8 @@ sub _row_to_result { return if $postcode_r->ward; $postcode_r->update( { ward_id => $ward->id } ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm index 5ba709a..d0df5c6 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm @@ -22,6 +22,8 @@ sub import_csv { while ( my $row = $self->get_csv_line ) { $self->_row_to_result($row); } + + return 1; } sub _row_to_result { @@ -56,6 +58,8 @@ sub _row_to_result { } } ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm index 1dfbeb4..c711a8b 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm @@ -46,6 +46,8 @@ sub import_csv { while ( my $row = $self->get_csv_line ) { $self->_row_to_result( $row, $lcc_org ); } + + return 1; } sub _row_to_result { @@ -181,6 +183,8 @@ sub _row_to_result { ), } ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm b/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm index 5ee6fec..b69cad3 100644 --- a/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm +++ b/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm @@ -176,7 +176,8 @@ sub register { return b($html); } ); - + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Currency.pm b/lib/Pear/LocalLoop/Plugin/Currency.pm index 68cec27..287b7ae 100644 --- a/lib/Pear/LocalLoop/Plugin/Currency.pm +++ b/lib/Pear/LocalLoop/Plugin/Currency.pm @@ -24,6 +24,8 @@ sub register { return sprintf( '£%.2f', $value / 100000 ); } ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Datetime.pm b/lib/Pear/LocalLoop/Plugin/Datetime.pm index c942656..2f94e1f 100644 --- a/lib/Pear/LocalLoop/Plugin/Datetime.pm +++ b/lib/Pear/LocalLoop/Plugin/Datetime.pm @@ -95,6 +95,7 @@ sub register { } ); + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion.pm b/lib/Pear/LocalLoop/Plugin/Minion.pm index c093c18..b4edba7 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion.pm @@ -34,7 +34,8 @@ sub register { else { $app->log->debug('No Minion Config'); } - + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm index 5511fa1..e1e491c 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm @@ -10,6 +10,8 @@ sub run { csv_file => $filename, schema => $self->app->schema )->import_csv; + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm index 8617517..d051b14 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm @@ -10,6 +10,8 @@ sub run { csv_file => $filename, schema => $self->app->schema )->import_csv; + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm index a6b7354..8ec0841 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm @@ -11,6 +11,8 @@ sub run { schema => $self->app->schema, target_entity_id => $entity_id, )->import_csv; + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm index 57014d4..48f6a20 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm @@ -30,6 +30,8 @@ sub run { } } } + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm index e1bbbfd..5046aa3 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm @@ -7,6 +7,8 @@ sub run { my $leaderboard_rs = $self->app->schema->resultset('Leaderboard'); $leaderboard_rs->recalculate_all; + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm index a02db92..6fd0230 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm @@ -8,6 +8,8 @@ sub run { for my $arg (@args) { $self->job->app->log->debug($arg); } + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Postcodes.pm b/lib/Pear/LocalLoop/Plugin/Postcodes.pm index 428648b..60e8ddf 100644 --- a/lib/Pear/LocalLoop/Plugin/Postcodes.pm +++ b/lib/Pear/LocalLoop/Plugin/Postcodes.pm @@ -71,6 +71,8 @@ sub register { return; } ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm b/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm index 55fac82..b540f0d 100644 --- a/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm +++ b/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm @@ -15,7 +15,8 @@ sub register { } } ); - + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Plugin/Validators.pm b/lib/Pear/LocalLoop/Plugin/Validators.pm index 207ec46..6acb616 100644 --- a/lib/Pear/LocalLoop/Plugin/Validators.pm +++ b/lib/Pear/LocalLoop/Plugin/Validators.pm @@ -101,6 +101,8 @@ sub register { ); $app->helper( validation_error => sub { _validation_error(@_) } ); + + return 1; } =head2 validation_error diff --git a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm index 06be273..a9be49e 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm @@ -146,6 +146,8 @@ sub sqlt_deploy_hook { else { $pending_field->{default_value} = \"false"; } + + return 1; } sub to_bool { diff --git a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm index d951d9e..5e96089 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm @@ -103,6 +103,8 @@ sub sqlt_deploy_hook { else { $pending_field->{default_value} = \"false"; } + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/User.pm b/lib/Pear/LocalLoop/Schema/Result/User.pm index 2e0de1b..4340470 100644 --- a/lib/Pear/LocalLoop/Schema/Result/User.pm +++ b/lib/Pear/LocalLoop/Schema/Result/User.pm @@ -84,6 +84,12 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); +__PACKAGE__->filter_column( + is_admin => { + filter_to_storage => 'to_bool', + } +); + sub sqlt_deploy_hook { my ( $source_instance, $sqlt_table ) = @_; my $pending_field = $sqlt_table->get_field('is_admin'); @@ -93,14 +99,10 @@ sub sqlt_deploy_hook { else { $pending_field->{default_value} = \"false"; } + + return 1; } -__PACKAGE__->filter_column( - is_admin => { - filter_to_storage => 'to_bool', - } -); - sub to_bool { my ( $self, $val ) = @_; my $driver_name = diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm index 3fdb4e1..eb89608 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm @@ -5,7 +5,7 @@ use warnings; use base 'DBIx::Class::ResultSet'; -sub sales { shift->search_related( 'sales', @_ ) } +sub sales { return shift->search_related( 'sales', @_ ) } sub create_org { my ( $self, $org ) = @_; @@ -16,6 +16,8 @@ sub create_org { type => 'organisation', } ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm index 2a1dedc..fdb794b 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm @@ -92,6 +92,8 @@ sub recalculate_all { warn "Unrecognised Set"; } } + + return 1; } sub _recalculate_leaderboard { @@ -105,6 +107,8 @@ sub _recalculate_leaderboard { $lb_result->create_new($date); } ); + + return 1; } 1; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm index db6ad56..afa028f 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm @@ -5,6 +5,6 @@ use warnings; use base 'DBIx::Class::ResultSet'; -sub entity { shift->search_related( 'entity', @_ ) } +sub entity { return shift->search_related( 'entity', @_ ) } 1; diff --git a/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm b/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm index 9f5b841..11b332a 100644 --- a/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm +++ b/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm @@ -207,6 +207,8 @@ sub cmd_write_ddl { } ); } + + return 1; } =head2 install_dh @@ -225,6 +227,8 @@ sub cmd_install_dh { version => $self->version, } ); + + return 1; } =head2 install @@ -241,6 +245,8 @@ sub cmd_install { version => $self->version, } ); + + return 1; } =head2 upgrade @@ -253,6 +259,8 @@ sub cmd_upgrade { my ($self) = @_; $self->dh->upgrade; + + return 1; } =head1 AUTHOR diff --git a/lib/Test/Pear/LocalLoop.pm b/lib/Test/Pear/LocalLoop.pm index 5da847c..2de5f80 100644 --- a/lib/Test/Pear/LocalLoop.pm +++ b/lib/Test/Pear/LocalLoop.pm @@ -14,6 +14,8 @@ sub BUILD { or die "you need Test::PostgreSQL to run PG testing"; Test::PostgreSQL->import; } + + return 1; } sub DEMOLISH { @@ -23,6 +25,8 @@ sub DEMOLISH { $self->mojo->app->schema->storage->dbh->disconnect; $self->pg->stop; } + + return 1; } has pg => ( @@ -141,6 +145,8 @@ sub register_customer { $self->framework->post_ok( '/api/register' => json => $json ) ->status_is(200)->or( $self->dump_error ) ->json_is( '/success', Mojo::JSON->true )->or( $self->dump_error ); + + return 1; } sub register_organisation { @@ -151,6 +157,8 @@ sub register_organisation { $self->framework->post_ok( '/api/register' => json => $args ) ->status_is(200)->or( $self->dump_error ) ->json_is( '/success', Mojo::JSON->true )->or( $self->dump_error ); + + return 1; } sub login { @@ -172,6 +180,8 @@ sub logout { '/api/logout' => json => { session_key => $session_key } ) ->status_is(200)->json_is( '/success', Mojo::JSON->true ) ->json_like( '/message', qr/Logged Out/ ); + + return 1; } sub gen_upload { @@ -187,6 +197,8 @@ sub gen_upload { json => Mojo::JSON::encode_json($args), file => $file, }; + + return 1; } sub install_fixtures { @@ -241,6 +253,8 @@ sub install_fixtures { } ); } + + return 1; } 1; From 758dd9e70f8ea09bbace2a550815290994997122 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 19:03:59 +0000 Subject: [PATCH 270/289] Fix builtin homonym linter errors --- lib/Pear/LocalLoop.pm | 38 +++++++++---------- .../LocalLoop/Controller/Admin/Categories.pm | 6 +-- .../LocalLoop/Controller/Admin/Feedback.pm | 4 +- lib/Pear/LocalLoop/Controller/Admin/Import.pm | 2 +- .../LocalLoop/Controller/Admin/ImportFrom.pm | 2 +- lib/Pear/LocalLoop/Controller/Admin/Tokens.pm | 6 +-- .../Controller/Admin/Transactions.pm | 6 +++ lib/Pear/LocalLoop/Controller/Admin/Users.pm | 6 +++ .../Controller/Api/V1/Customer/Graphs.pm | 2 +- .../Controller/Api/V1/Customer/Pies.pm | 2 +- .../Controller/Api/V1/Customer/Snippets.pm | 2 +- .../Controller/Api/V1/Organisation/Graphs.pm | 2 +- .../Controller/Api/V1/Organisation/Pies.pm | 2 +- .../Api/V1/Organisation/Snippets.pm | 2 +- .../Controller/Api/V1/Supplier/Location.pm | 2 +- .../Controller/Api/V1/User/Medals.pm | 2 +- .../Controller/Api/V1/User/Points.pm | 2 +- lib/Pear/LocalLoop/Controller/Root.pm | 2 + 18 files changed, 52 insertions(+), 38 deletions(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 5f04a65..7ace853 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -216,20 +216,20 @@ sub startup { my $api_v1_user = $api_v1->under('/user'); - $api_v1_user->post('/medals')->to('api-v1-user-medals#index'); - $api_v1_user->post('/points')->to('api-v1-user-points#index'); + $api_v1_user->post('/medals')->to('api-v1-user-medals#idx'); + $api_v1_user->post('/points')->to('api-v1-user-points#idx'); my $api_v1_supplier = $api_v1->under('/supplier'); - $api_v1_supplier->post('/location')->to('api-v1-supplier-location#index'); + $api_v1_supplier->post('/location')->to('api-v1-supplier-location#idx'); $api_v1_supplier->post('/location/trail') ->to('api-v1-supplier-location#trail_load'); my $api_v1_org = $api_v1->under('/organisation')->to('api-v1-organisation#auth'); - $api_v1_org->post('/graphs')->to('api-v1-organisation-graphs#index'); - $api_v1_org->post('/snippets')->to('api-v1-organisation-snippets#index'); + $api_v1_org->post('/graphs')->to('api-v1-organisation-graphs#idx'); + $api_v1_org->post('/snippets')->to('api-v1-organisation-snippets#idx'); $api_v1_org->post('/payroll')->to('api-organisation#post_payroll_read'); $api_v1_org->post('/payroll/add')->to('api-organisation#post_payroll_add'); $api_v1_org->post('/supplier')->to('api-organisation#post_supplier_read'); @@ -252,13 +252,13 @@ sub startup { $api_v1_org->post('/external/lcc_tables') ->to('api-external#post_lcc_table_summary'); - $api_v1_org->post('/pies')->to('api-v1-organisation-pies#index'); + $api_v1_org->post('/pies')->to('api-v1-organisation-pies#idx'); my $api_v1_cust = $api_v1->under('/customer')->to('api-v1-customer#auth'); - $api_v1_cust->post('/graphs')->to('api-v1-customer-graphs#index'); - $api_v1_cust->post('/snippets')->to('api-v1-customer-snippets#index'); - $api_v1_cust->post('/pies')->to('api-v1-customer-pies#index'); + $api_v1_cust->post('/graphs')->to('api-v1-customer-graphs#idx'); + $api_v1_cust->post('/snippets')->to('api-v1-customer-snippets#idx'); + $api_v1_cust->post('/pies')->to('api-v1-customer-pies#idx'); my $admin_routes = $r->under('/admin')->to('admin#under'); @@ -272,18 +272,18 @@ sub startup { } $admin_routes->get('/home')->to('admin#home'); - $admin_routes->get('/tokens')->to('admin-tokens#index'); + $admin_routes->get('/tokens')->to('admin-tokens#idx'); $admin_routes->post('/tokens')->to('admin-tokens#create'); - $admin_routes->get('/tokens/:id')->to('admin-tokens#read'); + $admin_routes->get('/tokens/:id')->to('admin-tokens#get'); $admin_routes->post('/tokens/:id')->to('admin-tokens#update'); - $admin_routes->post('/tokens/:id/delete')->to('admin-tokens#delete'); + $admin_routes->post('/tokens/:id/delete')->to('admin-tokens#del'); - $admin_routes->get('/categories')->to('admin-categories#index'); + $admin_routes->get('/categories')->to('admin-categories#idx'); $admin_routes->post('/categories')->to('admin-categories#create'); - $admin_routes->get('/categories/:id')->to('admin-categories#read'); + $admin_routes->get('/categories/:id')->to('admin-categories#get'); $admin_routes->post('/categories/:id')->to('admin-categories#update'); $admin_routes->post('/categories/:id/delete') - ->to('admin-categories#delete'); + ->to('admin-categories#del'); $admin_routes->get('/users')->to('admin-users#index'); $admin_routes->get('/users/:id')->to('admin-users#read'); @@ -305,8 +305,8 @@ sub startup { $admin_routes->post('/organisations/:id/merge/:target_id') ->to('admin-organisations#merge_confirm'); - $admin_routes->get('/feedback')->to('admin-feedback#index'); - $admin_routes->get('/feedback/:id')->to('admin-feedback#read'); + $admin_routes->get('/feedback')->to('admin-feedback#idx'); + $admin_routes->get('/feedback/:id')->to('admin-feedback#get'); $admin_routes->get('/feedback/:id/actioned')->to('admin-feedback#actioned'); $admin_routes->get('/transactions')->to('admin-transactions#index'); @@ -319,7 +319,7 @@ sub startup { $admin_routes->get('/reports/transactions') ->to('admin-reports#transaction_data'); - $admin_routes->get('/import')->to('admin-import#index'); + $admin_routes->get('/import')->to('admin-import#idx'); $admin_routes->get('/import/add')->to('admin-import#get_add'); $admin_routes->post('/import/add')->to('admin-import#post_add'); $admin_routes->get('/import/:set_id')->to('admin-import#list'); @@ -330,7 +330,7 @@ sub startup { ->to('admin-import#ignore_value'); $admin_routes->get('/import/:set_id/import')->to('admin-import#run_import'); - $admin_routes->get('/import_from')->to('admin-import_from#index'); + $admin_routes->get('/import_from')->to('admin-import_from#idx'); $admin_routes->post('/import_from/suppliers') ->to('admin-import_from#post_suppliers'); $admin_routes->post('/import_from/transactions') diff --git a/lib/Pear/LocalLoop/Controller/Admin/Categories.pm b/lib/Pear/LocalLoop/Controller/Admin/Categories.pm index 53a3698..bb539c6 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Categories.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Categories.pm @@ -6,7 +6,7 @@ has result_set => sub { return $c->schema->resultset('Category'); }; -sub index { +sub idx { my $c = shift; my $category_rs = $c->result_set; @@ -50,7 +50,7 @@ sub create { } # GET -sub read { +sub get { my $c = shift; my $id = $c->param('id'); @@ -106,7 +106,7 @@ sub update { } # DELETE -sub delete { +sub del { my $c = shift; my $id = $c->param('id'); diff --git a/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm b/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm index 048f2af..2a39fb1 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm @@ -6,7 +6,7 @@ has result_set => sub { return $c->schema->resultset('Feedback'); }; -sub index { +sub idx { my $c = shift; my $feedback_rs = $c->result_set->search( @@ -22,7 +22,7 @@ sub index { return 1; } -sub read { +sub get { my $c = shift; my $id = $c->param('id'); diff --git a/lib/Pear/LocalLoop/Controller/Admin/Import.pm b/lib/Pear/LocalLoop/Controller/Admin/Import.pm index 4d1b0ee..4ef8f34 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Import.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Import.pm @@ -9,7 +9,7 @@ has result_set => sub { return $c->schema->resultset('ImportSet'); }; -sub index { +sub idx { my $c = shift; my $import_rs = $c->result_set->search( diff --git a/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm b/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm index e8b47af..b55916f 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm @@ -4,7 +4,7 @@ use Moo; use Try::Tiny; use Mojo::File qw/path/; -sub index { +sub idx { my $c = shift; $c->stash->{org_entities} = [ map { { id => $_->entity_id, name => $_->name } } diff --git a/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm b/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm index 887f2a8..eb3ec8d 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm @@ -6,7 +6,7 @@ has result_set => sub { return $c->schema->resultset('AccountToken'); }; -sub index { +sub idx { my $c = shift; my $token_rs = $c->result_set; @@ -50,7 +50,7 @@ sub create { } # GET -sub read { +sub get { my $c = shift; my $id = $c->param('id'); @@ -100,7 +100,7 @@ sub update { } # DELETE -sub delete { +sub del { my $c = shift; my $id = $c->param('id'); diff --git a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm index a1833a4..23d5b18 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm @@ -8,7 +8,9 @@ has result_set => sub { return $c->schema->resultset('Transaction'); }; +## no critic (Subroutines::ProhibitBuiltinHomonyms) sub index { +## use critic my $c = shift; my $pending_transaction_rs = @@ -70,7 +72,9 @@ sub index { return 1; } +## no critic (Subroutines::ProhibitBuiltinHomonyms) sub read { +## use critic my $c = shift; my $id = $c->param('id'); @@ -103,7 +107,9 @@ sub image { return 1; } +## no critic (Subroutines::ProhibitBuiltinHomonyms) sub delete { +## use critic my $c = shift; my $id = $c->param('id'); diff --git a/lib/Pear/LocalLoop/Controller/Admin/Users.pm b/lib/Pear/LocalLoop/Controller/Admin/Users.pm index f5a2126..edd76b4 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Users.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Users.pm @@ -19,7 +19,9 @@ has organisation_result_set => sub { return $c->schema->resultset('Organisation'); }; +## no critic (Subroutines::ProhibitBuiltinHomonyms) sub index { +## use critic my $c = shift; my $user_rs = $c->user_result_set->search( @@ -36,7 +38,9 @@ sub index { return 1; } +## no critic (Subroutines::ProhibitBuiltinHomonyms) sub read { +## use critic my $c = shift; my $id = $c->param('id'); @@ -63,7 +67,9 @@ sub read { return 1; } +## no critic (Subroutines::ProhibitBuiltinHomonyms) sub update { +## use critic my $c = shift; my $id = $c->param('id'); diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm index 5e927ac..b636c9b 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Graphs.pm @@ -10,7 +10,7 @@ has error_messages => sub { }; }; -sub index { +sub idx { my $c = shift; my $validation = $c->validation; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm index 30e2123..a39a776 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm @@ -1,7 +1,7 @@ package Pear::LocalLoop::Controller::Api::V1::Customer::Pies; use Mojo::Base 'Mojolicious::Controller'; -sub index { +sub idx { my $c = shift; my $entity = $c->stash->{api_user}->entity; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm index a7daca2..682947b 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Snippets.pm @@ -1,7 +1,7 @@ package Pear::LocalLoop::Controller::Api::V1::Customer::Snippets; use Mojo::Base 'Mojolicious::Controller'; -sub index { +sub idx { my $c = shift; my $entity = $c->stash->{api_user}->entity; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm index 5108804..462d066 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Graphs.pm @@ -10,7 +10,7 @@ has error_messages => sub { }; }; -sub index { +sub idx { my $c = shift; my $validation = $c->validation; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Pies.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Pies.pm index f554618..dcd4bd5 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Pies.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Pies.pm @@ -1,7 +1,7 @@ package Pear::LocalLoop::Controller::Api::V1::Organisation::Pies; use Mojo::Base 'Mojolicious::Controller'; -sub index { +sub idx { my $c = shift; my $entity = $c->stash->{api_user}->entity; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm index ddc5fe4..ababef2 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Organisation/Snippets.pm @@ -1,7 +1,7 @@ package Pear::LocalLoop::Controller::Api::V1::Organisation::Snippets; use Mojo::Base 'Mojolicious::Controller'; -sub index { +sub idx { my $c = shift; my $entity = $c->stash->{api_user}->entity; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm index 3fec296..ae5d049 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm @@ -47,7 +47,7 @@ has validation_data => sub { }; }; -sub index { +sub idx { my $c = shift; return if $c->validation_error('index'); diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/User/Medals.pm b/lib/Pear/LocalLoop/Controller/Api/V1/User/Medals.pm index 8a10846..f920ec5 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/User/Medals.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/User/Medals.pm @@ -2,7 +2,7 @@ package Pear::LocalLoop::Controller::Api::V1::User::Medals; use Mojo::Base 'Mojolicious::Controller'; use Mojo::JSON qw/true false/; -sub index { +sub idx { my $c = shift; my $validation = $c->validation; diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/User/Points.pm b/lib/Pear/LocalLoop/Controller/Api/V1/User/Points.pm index 688cd90..3d32421 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/User/Points.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/User/Points.pm @@ -2,7 +2,7 @@ package Pear::LocalLoop::Controller::Api::V1::User::Points; use Mojo::Base 'Mojolicious::Controller'; use Mojo::JSON qw/true false/; -sub index { +sub idx { my $c = shift; my $validation = $c->validation; diff --git a/lib/Pear/LocalLoop/Controller/Root.pm b/lib/Pear/LocalLoop/Controller/Root.pm index 6ed1bb9..9106a7f 100644 --- a/lib/Pear/LocalLoop/Controller/Root.pm +++ b/lib/Pear/LocalLoop/Controller/Root.pm @@ -1,7 +1,9 @@ package Pear::LocalLoop::Controller::Root; use Mojo::Base 'Mojolicious::Controller'; +## no critic (Subroutines::ProhibitBuiltinHomonyms) sub index { +## use critic my $c = shift; # if ( $c->is_user_authenticated ) { From 6399354b809da92d52a81c84e4b5fbef21dad187 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 19:04:08 +0000 Subject: [PATCH 271/289] Update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 75e4256..5cee2b7 100644 --- a/README.md +++ b/README.md @@ -119,8 +119,8 @@ Run `./script/pear-local_loop recalc_leaderboards` to update the leaderboards. ## Testing -- Run `prove -lr` to run the full test suite using [Test-Simple](https://metacpan.org/release/Test-Simple) (when using an SQLite database); and -- run `PEAR_TEST_PG=1 prove -lr` to run the full test suite (when using a PostgreSQL database). +- Run `prove -lr -j 9` to run the full test suite using [Test-Simple](https://metacpan.org/release/Test-Simple) (when using an SQLite database); and +- run `PEAR_TEST_PG=1 prove -lr -j 9` to run the full test suite (when using a PostgreSQL database). Test files are found in the `t/` directory. From 1f6225e506ffee02d48eb967ab178c6cea9c858f Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 19:53:38 +0000 Subject: [PATCH 272/289] Fix remaining linter errors --- lib/Pear/LocalLoop/Controller/Admin/Import.pm | 4 ++++ lib/Pear/LocalLoop/Controller/Admin/Organisations.pm | 6 +++--- lib/Pear/LocalLoop/Controller/Admin/Users.pm | 10 +++++----- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 6 +++++- lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm | 2 ++ lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm | 4 ++-- lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm | 8 ++++---- lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm | 2 ++ lib/Test/Pear/LocalLoop.pm | 4 +--- 9 files changed, 28 insertions(+), 18 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Import.pm b/lib/Pear/LocalLoop/Controller/Admin/Import.pm index 4ef8f34..43a8945 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Import.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Import.pm @@ -71,6 +71,7 @@ sub post_add { } ); + ## no critic (InputOutput::RequireBriefOpen) open my $fh, '<', \$csv_data; # List context returns the actual headers @@ -99,6 +100,9 @@ sub post_add { } my $csv_output = $csv->getline_hr_all($fh); + + close $fh; + ## use critic unless ( scalar(@$csv_output) ) { $c->_csv_flash_error("No data found"); diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 5b05a42..620949f 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -123,7 +123,7 @@ sub valid_read { } sub valid_edit { - my $c = shift; + my ($c, $warning) = @_; my $validation = $c->validation; $validation->required('name'); @@ -180,9 +180,9 @@ sub valid_edit { ); } finally { - if (@_) { + if ($warning) { use Devel::Dwarn; - Dwarn \@_; + Dwarn \$warning; $c->flash( error => 'Something went wrong Updating the Organisation' ); } diff --git a/lib/Pear/LocalLoop/Controller/Admin/Users.pm b/lib/Pear/LocalLoop/Controller/Admin/Users.pm index edd76b4..292a0f9 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Users.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Users.pm @@ -70,7 +70,7 @@ sub read { ## no critic (Subroutines::ProhibitBuiltinHomonyms) sub update { ## use critic - my $c = shift; + my ($c, $error) = @_; my $id = $c->param('id'); @@ -145,9 +145,9 @@ sub update { ); } finally { - if (@_) { + if ($error) { $c->flash( error => 'Something went wrong Updating the User' ); - $c->app->log->warn( Dumper @_ ); + $c->app->log->warn( Dumper $error ); } else { $c->flash( success => 'Updated User' ); @@ -188,9 +188,9 @@ sub update { ); } finally { - if (@_) { + if ($error) { $c->flash( error => 'Something went wrong Updating the User' ); - $c->app->log->warn( Dumper @_ ); + $c->app->log->warn( Dumper $error ); } else { $c->flash( success => 'Updated User' ); diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index 25278fb..2e8bef1 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -460,14 +460,16 @@ sub post_leaderboards { my @leaderboard_array = $today_values->all; if ( $validation->param('type') =~ /total$/ ) { + ## no critic (ValuesAndExpressions::ProhibitCommaSeparatedStatements) @leaderboard_array = ( map { { %$_, - value => $_->{value} / 100000, + value => $_->{value} / 100000 } } @leaderboard_array ); + ## use critic } my $current_user_position = @@ -543,6 +545,7 @@ sub post_leaderboards_paged { $values_count = $today_values->pager->total_entries; if ( $validation->param('type') =~ /total$/ ) { + ## no critic (ValuesAndExpressions::ProhibitCommaSeparatedStatements) @leaderboard_array = ( map { { @@ -551,6 +554,7 @@ sub post_leaderboards_paged { } } @leaderboard_array ); + ## use critic } $current_user_position = $today_values->find( diff --git a/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm index 287a8b9..4de3d20 100644 --- a/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm @@ -34,3 +34,5 @@ __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( "entity", "Pear::LocalLoop::Schema::Result::Entity", "entity_id", ); + +1; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm index eb89608..392046e 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Entity.pm @@ -5,7 +5,9 @@ use warnings; use base 'DBIx::Class::ResultSet'; +## no critic (Subroutines::RequireArgUnpacking) sub sales { return shift->search_related( 'sales', @_ ) } +## use critic sub create_org { my ( $self, $org ) = @_; @@ -16,8 +18,6 @@ sub create_org { type => 'organisation', } ); - - return 1; } 1; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm b/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm index b7964e5..186425e 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm @@ -39,9 +39,9 @@ sub _unordered_get_values { } sub get_users { - my $self = shift; + my ($self, $set_id) = @_; - return $self->_unordered_get_values(@_)->search( + return $self->_unordered_get_values($set_id)->search( {}, { group_by => 'user_name', @@ -51,9 +51,9 @@ sub get_users { } sub get_orgs { - my $self = shift; + my ( $self, $set_id ) = shift; - return $self->_unordered_get_values(@_)->search( + return $self->_unordered_get_values($set_id)->search( {}, { group_by => 'org_name', diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm index afa028f..a8ef125 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Organisation.pm @@ -5,6 +5,8 @@ use warnings; use base 'DBIx::Class::ResultSet'; +## no critic (Subroutines::RequireArgUnpacking) sub entity { return shift->search_related( 'entity', @_ ) } +## use critic 1; diff --git a/lib/Test/Pear/LocalLoop.pm b/lib/Test/Pear/LocalLoop.pm index 2de5f80..5119cfb 100644 --- a/lib/Test/Pear/LocalLoop.pm +++ b/lib/Test/Pear/LocalLoop.pm @@ -69,7 +69,7 @@ has mojo => ( builder => sub { my $self = shift; - $ENV{MOJO_CONFIG} = $self->config->filename; + local $ENV{MOJO_CONFIG} = $self->config->filename; my $t = Test::Mojo->new('Pear::LocalLoop'); $t->app->schema->deploy; @@ -197,8 +197,6 @@ sub gen_upload { json => Mojo::JSON::encode_json($args), file => $file, }; - - return 1; } sub install_fixtures { From bec21ff3e03930796b751775c72709faa810b9d9 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 23:26:29 +0000 Subject: [PATCH 273/289] Add default topic creation --- lib/Pear/LocalLoop/Command/dev_data.pm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Command/dev_data.pm b/lib/Pear/LocalLoop/Command/dev_data.pm index c230c4a..759a539 100644 --- a/lib/Pear/LocalLoop/Command/dev_data.pm +++ b/lib/Pear/LocalLoop/Command/dev_data.pm @@ -90,7 +90,13 @@ sub run { }, } ); - + + $c->schema->resultset('DeviceToken')->create( + { + name => 'default' + } + ); + return 1; } From a0dd7dd1747f3b233d5e82f214e382e6dda4475d Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 23:26:52 +0000 Subject: [PATCH 274/289] Format --- lib/Pear/LocalLoop.pm | 4 +- lib/Pear/LocalLoop/Command/codepoint_open.pm | 2 +- .../LocalLoop/Command/dev_transactions.pm | 2 +- lib/Pear/LocalLoop/Command/latlong_setup.pm | 4 +- lib/Pear/LocalLoop/Command/leaderboard.pm | 2 +- .../LocalLoop/Command/recalc_leaderboards.pm | 2 +- .../LocalLoop/Command/recur_transactions.pm | 2 +- lib/Pear/LocalLoop/Controller/Admin.pm | 6 +-- .../LocalLoop/Controller/Admin/Categories.pm | 10 ++--- .../LocalLoop/Controller/Admin/Feedback.pm | 6 +-- lib/Pear/LocalLoop/Controller/Admin/Import.pm | 18 ++++---- .../LocalLoop/Controller/Admin/ImportFrom.pm | 9 ++-- .../Controller/Admin/Organisations.pm | 18 ++++---- .../LocalLoop/Controller/Admin/Reports.pm | 2 +- lib/Pear/LocalLoop/Controller/Admin/Tokens.pm | 10 ++--- .../Controller/Admin/Transactions.pm | 8 ++-- lib/Pear/LocalLoop/Controller/Admin/Users.pm | 8 ++-- lib/Pear/LocalLoop/Controller/Api/Auth.pm | 4 +- .../LocalLoop/Controller/Api/Sendmessage.pm | 13 +----- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 7 ++- .../Controller/Api/V1/Supplier/Location.pm | 4 +- lib/Pear/LocalLoop/Controller/Root.pm | 8 ++-- lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm | 4 +- lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm | 7 +-- .../LocalLoop/Import/LCCCsv/Transactions.pm | 4 +- .../LocalLoop/Plugin/BootstrapPagination.pm | 45 ++++++++++++------- lib/Pear/LocalLoop/Plugin/Currency.pm | 2 +- lib/Pear/LocalLoop/Plugin/Minion.pm | 2 +- .../Plugin/Minion/Job/csv_postcode_import.pm | 2 +- .../Plugin/Minion/Job/csv_supplier_import.pm | 2 +- .../Minion/Job/csv_transaction_import.pm | 2 +- .../Minion/Job/entity_postcode_lookup.pm | 2 +- .../Plugin/Minion/Job/leaderboards_recalc.pm | 2 +- lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm | 2 +- lib/Pear/LocalLoop/Plugin/Postcodes.pm | 2 +- lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm | 2 +- lib/Pear/LocalLoop/Plugin/Validators.pm | 2 +- .../Schema/Result/EntityAssociation.pm | 2 +- .../LocalLoop/Schema/Result/Organisation.pm | 2 +- .../LocalLoop/Schema/Result/Transaction.pm | 2 +- lib/Pear/LocalLoop/Schema/Result/User.pm | 2 +- .../LocalLoop/Schema/ResultSet/Category.pm | 12 ++--- .../LocalLoop/Schema/ResultSet/ImportSet.pm | 2 +- .../LocalLoop/Schema/ResultSet/Leaderboard.pm | 4 +- .../Schema/Script/DeploymentHandler.pm | 8 ++-- lib/Test/Pear/LocalLoop.pm | 12 ++--- 46 files changed, 138 insertions(+), 139 deletions(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 7ace853..a58e075 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -173,6 +173,7 @@ sub startup { $api_public->post('/register')->to('api-register#post_register'); $api_public->post('/logout')->to('api-auth#post_logout'); $api_public->post('/feedback')->to('api-feedback#post_feedback'); + $api_public->post('/check-device-token')->to('api-devices#check_token'); $api_public->post('/add-device-token')->to('api-devices#add_token'); $api_public->post('/get-topics')->to('api-sendmessage#get_topics'); @@ -282,8 +283,7 @@ sub startup { $admin_routes->post('/categories')->to('admin-categories#create'); $admin_routes->get('/categories/:id')->to('admin-categories#get'); $admin_routes->post('/categories/:id')->to('admin-categories#update'); - $admin_routes->post('/categories/:id/delete') - ->to('admin-categories#del'); + $admin_routes->post('/categories/:id/delete')->to('admin-categories#del'); $admin_routes->get('/users')->to('admin-users#index'); $admin_routes->get('/users/:id')->to('admin-users#read'); diff --git a/lib/Pear/LocalLoop/Command/codepoint_open.pm b/lib/Pear/LocalLoop/Command/codepoint_open.pm index b4570b4..adcaf0e 100644 --- a/lib/Pear/LocalLoop/Command/codepoint_open.pm +++ b/lib/Pear/LocalLoop/Command/codepoint_open.pm @@ -55,7 +55,7 @@ sub run { { key => 'primary' }, ); } - + return 1; } diff --git a/lib/Pear/LocalLoop/Command/dev_transactions.pm b/lib/Pear/LocalLoop/Command/dev_transactions.pm index adcdf51..614f723 100644 --- a/lib/Pear/LocalLoop/Command/dev_transactions.pm +++ b/lib/Pear/LocalLoop/Command/dev_transactions.pm @@ -90,7 +90,7 @@ sub run { } } } - + return 1; } diff --git a/lib/Pear/LocalLoop/Command/latlong_setup.pm b/lib/Pear/LocalLoop/Command/latlong_setup.pm index 9c34136..81c0db7 100644 --- a/lib/Pear/LocalLoop/Command/latlong_setup.pm +++ b/lib/Pear/LocalLoop/Command/latlong_setup.pm @@ -29,7 +29,7 @@ sub run { ); $result->update( { distance => $distance } ) if defined $distance; } - + return 1; } @@ -55,7 +55,7 @@ sub _set_lat_long_for_result { ); } } - + return 1; } diff --git a/lib/Pear/LocalLoop/Command/leaderboard.pm b/lib/Pear/LocalLoop/Command/leaderboard.pm index bd5df60..91c09b6 100644 --- a/lib/Pear/LocalLoop/Command/leaderboard.pm +++ b/lib/Pear/LocalLoop/Command/leaderboard.pm @@ -71,7 +71,7 @@ sub run { } } } - + return 1; } diff --git a/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm b/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm index 5ea8fa5..ed61d6e 100644 --- a/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm +++ b/lib/Pear/LocalLoop/Command/recalc_leaderboards.pm @@ -13,7 +13,7 @@ sub run { my $leaderboard_rs = $self->app->schema->resultset('Leaderboard'); $leaderboard_rs->recalculate_all; - + return 1; } diff --git a/lib/Pear/LocalLoop/Command/recur_transactions.pm b/lib/Pear/LocalLoop/Command/recur_transactions.pm index 58bf927..78268f8 100644 --- a/lib/Pear/LocalLoop/Command/recur_transactions.pm +++ b/lib/Pear/LocalLoop/Command/recur_transactions.pm @@ -153,7 +153,7 @@ sub run { $recur_result->update( { last_updated => $purchase_time } ); } - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Admin.pm b/lib/Pear/LocalLoop/Controller/Admin.pm index 01049d3..e130761 100644 --- a/lib/Pear/LocalLoop/Controller/Admin.pm +++ b/lib/Pear/LocalLoop/Controller/Admin.pm @@ -34,7 +34,7 @@ sub home { pending => $pending_feedback_rs->count, }, ); - + return 1; } @@ -54,7 +54,7 @@ sub auth_login { . "]" ); $c->redirect_to('/admin'); } - + return 1; } @@ -63,7 +63,7 @@ sub auth_logout { $c->logout; $c->redirect_to('/admin'); - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Admin/Categories.pm b/lib/Pear/LocalLoop/Controller/Admin/Categories.pm index bb539c6..c5b1687 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Categories.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Categories.pm @@ -12,7 +12,7 @@ sub idx { my $category_rs = $c->result_set; $category_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); $c->stash( categories => [ $category_rs->all ] ); - + return 1; } @@ -45,7 +45,7 @@ sub create { $c->result_set->create( { name => $category_name } ); } $c->redirect_to('/admin/categories'); - + return 1; } @@ -62,7 +62,7 @@ sub get { $c->flash( error => 'No Category found' ); $c->redirect_to('/admin/categories'); } - + return 1; } @@ -101,7 +101,7 @@ sub update { $c->flash( error => 'No Category found' ); $c->redirect_to('/admin/categories'); } - + return 1; } @@ -120,7 +120,7 @@ sub del { $c->flash( error => 'No Category found' ); } $c->redirect_to('/admin/categories'); - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm b/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm index 2a39fb1..ccffb5e 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Feedback.pm @@ -18,7 +18,7 @@ sub idx { }, ); $c->stash( feedback_rs => $feedback_rs ); - + return 1; } @@ -34,7 +34,7 @@ sub get { $c->flash( error => 'No Feedback found' ); $c->redirect_to('/admin/feedback'); } - + return 1; } @@ -52,7 +52,7 @@ sub actioned { $c->flash( error => 'No Feedback found' ); $c->redirect_to('/admin/feedback'); } - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Admin/Import.pm b/lib/Pear/LocalLoop/Controller/Admin/Import.pm index 43a8945..01514ed 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Import.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Import.pm @@ -21,7 +21,7 @@ sub idx { }, ); $c->stash( import_rs => $import_rs ); - + return 1; } @@ -48,13 +48,13 @@ sub list { import_org_rs => $import_org_rs, import_lookup_rs => $import_lookup_rs, ); - + return 1; } sub get_add { my $c = shift; - + return 1; } @@ -71,7 +71,7 @@ sub post_add { } ); - ## no critic (InputOutput::RequireBriefOpen) + ## no critic (InputOutput::RequireBriefOpen) open my $fh, '<', \$csv_data; # List context returns the actual headers @@ -100,7 +100,7 @@ sub post_add { } my $csv_output = $csv->getline_hr_all($fh); - + close $fh; ## use critic @@ -157,7 +157,7 @@ sub post_add { $c->flash( success => 'Created Value Set' ); $c->redirect_to( '/admin/import/' . $value_set->id ); - + return 1; } @@ -172,7 +172,7 @@ sub _csv_flash_error { #csv_data => $c->param('csv'), date_format => $c->param('date_format'), ); - + return 1; } @@ -223,7 +223,7 @@ sub get_user { lookup => $lookup_result, user_name => $user_name, ); - + return 1; } @@ -274,7 +274,7 @@ sub get_org { lookup => $lookup_result, org_name => $org_name, ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm b/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm index b55916f..2c08780 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/ImportFrom.pm @@ -15,7 +15,7 @@ sub idx { ]; $c->app->max_request_size(104857600); - + return 1; } @@ -127,12 +127,11 @@ sub org_search { }, ); - my @results = ( - map { { label => $_->name, value => $_->entity->id, } } $rs->all - ); + my @results = + ( map { { label => $_->name, value => $_->entity->id, } } $rs->all ); $c->render( json => \@results ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm index 620949f..e9cd313 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Organisations.pm @@ -21,13 +21,13 @@ sub list { ); $c->stash( orgs_rs => $orgs_rs, ); - + return 1; } sub add_org { my $c = shift; - + return 1; } @@ -91,7 +91,7 @@ sub add_org_submit { $c->redirect_to( '/admin/organisations/' . $organisation->id ); } }; - + return 1; } @@ -118,12 +118,12 @@ sub valid_read { transactions => $transactions, associations => $assoc, ); - + return 1; } sub valid_edit { - my ($c, $warning) = @_; + my ( $c, $warning ) = @_; my $validation = $c->validation; $validation->required('name'); @@ -191,7 +191,7 @@ sub valid_edit { } }; $c->redirect_to( '/admin/organisations/' . $c->param('id') ); - + return 1; } @@ -222,7 +222,7 @@ sub merge_list { org_result => $org_result, org_rs => $org_rs, ); - + return 1; } @@ -251,7 +251,7 @@ sub merge_detail { org_result => $org_result, target_result => $target_result, ); - + return 1; } @@ -309,7 +309,7 @@ sub merge_confirm { } $c->redirect_to( '/admin/organisations/' . $org_id . '/merge/' . $target_id ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm index 8040fdf..6362701 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm @@ -59,7 +59,7 @@ sub transaction_data { json => { json => { data => $transaction_data } }, html => { transaction_rs => encode_json($transaction_data) }, ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm b/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm index eb3ec8d..356a372 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Tokens.pm @@ -12,7 +12,7 @@ sub idx { my $token_rs = $c->result_set; $token_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); $c->stash( tokens => [ $token_rs->all ] ); - + return 1; } @@ -45,7 +45,7 @@ sub create { $c->result_set->create( { name => $token_name } ); } $c->redirect_to('/admin/tokens'); - + return 1; } @@ -62,7 +62,7 @@ sub get { $c->flash( error => 'No Token found' ); $c->redirect_to('/admin/tokens'); } - + return 1; } @@ -95,7 +95,7 @@ sub update { $c->flash( error => 'No Token found' ); $c->redirect_to('/admin/tokens'); } - + return 1; } @@ -113,7 +113,7 @@ sub del { $c->flash( error => 'No Token found' ); } $c->redirect_to('/admin/tokens'); - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm index 23d5b18..a88902f 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Transactions.pm @@ -68,7 +68,7 @@ sub index { count => $count, }, ); - + return 1; } @@ -86,7 +86,7 @@ sub read { $c->flash( error => 'No transaction found' ); $c->redirect_to('/admin/transactions'); } - + return 1; } @@ -103,7 +103,7 @@ sub image { else { $c->reply->static('image/no_transaction.jpg'); } - + return 1; } @@ -126,7 +126,7 @@ sub delete { $c->flash( error => 'No transaction found' ); $c->redirect_to('/admin/transactions'); } - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Admin/Users.pm b/lib/Pear/LocalLoop/Controller/Admin/Users.pm index 292a0f9..b77589e 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Users.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Users.pm @@ -34,7 +34,7 @@ sub index { } ); $c->stash( user_rs => $user_rs ); - + return 1; } @@ -63,14 +63,14 @@ sub read { $c->flash( error => 'No User found' ); $c->redirect_to('/admin/users'); } - + return 1; } ## no critic (Subroutines::ProhibitBuiltinHomonyms) sub update { ## use critic - my ($c, $error) = @_; + my ( $c, $error ) = @_; my $id = $c->param('id'); @@ -199,7 +199,7 @@ sub update { } $c->redirect_to( '/admin/users/' . $id ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Api/Auth.pm b/lib/Pear/LocalLoop/Controller/Api/Auth.pm index 64ca702..a40d6a7 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Auth.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Auth.pm @@ -124,6 +124,8 @@ sub post_login { sub post_logout { my $c = shift; + print STDERR "TEST"; + my $session_key = $c->req->json('/session_key'); my $session_result = @@ -139,7 +141,7 @@ sub post_logout { message => 'Logged Out', } ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm index 399360e..3cbee6a 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm @@ -9,10 +9,6 @@ use Carp; has error_messages => sub { return { - #devicetokens => { - # required => { message => 'Device token is required', status => 400 }, - # in_resultset => { message => 'Device token not found', status => 400 }, - #}, topic => { required => { message => 'Topic is required', status => 400 }, }, @@ -27,12 +23,8 @@ has error_messages => sub { }; }; -=begin comment - Credit: Peter Scott/StackOverflow - https://stackoverflow.com/a/53357961/4580273 - Credit: jeffez/StackOverflow - https://stackoverflow.com/q/56556438/4580273 -=cut +# Credit: Peter Scott/StackOverflow https://stackoverflow.com/a/53357961/4580273 +# Credit: jeffez/StackOverflow https://stackoverflow.com/q/56556438/4580273 my $jwt = create_jwt_from_path_and_scopes( './localspend-47012.json', 'email https://www.googleapis.com/auth/cloud-platform' ); @@ -104,7 +96,6 @@ sub post_message { my $validation = $c->validation; $validation->input( $c->stash->{api_json} ); -#$validation->required('devicetokens')->in_resultset('token', $c->schema->resultset('DeviceToken')); $validation->required('topic'); $validation->required('sender') ->in_resultset( 'name', $c->schema->resultset('Organisation') ); diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index 2e8bef1..e4afde4 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -460,12 +460,11 @@ sub post_leaderboards { my @leaderboard_array = $today_values->all; if ( $validation->param('type') =~ /total$/ ) { - ## no critic (ValuesAndExpressions::ProhibitCommaSeparatedStatements) + ## no critic (ValuesAndExpressions::ProhibitCommaSeparatedStatements) @leaderboard_array = ( map { { - %$_, - value => $_->{value} / 100000 + %$_, value => $_->{value} / 100000 } } @leaderboard_array ); @@ -545,7 +544,7 @@ sub post_leaderboards_paged { $values_count = $today_values->pager->total_entries; if ( $validation->param('type') =~ /total$/ ) { - ## no critic (ValuesAndExpressions::ProhibitCommaSeparatedStatements) + ## no critic (ValuesAndExpressions::ProhibitCommaSeparatedStatements) @leaderboard_array = ( map { { diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm index ae5d049..087287e 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Supplier/Location.pm @@ -122,7 +122,7 @@ sub idx { } }, ); - + return 1; } @@ -206,7 +206,7 @@ sub trail_load { } }, ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Root.pm b/lib/Pear/LocalLoop/Controller/Root.pm index 9106a7f..bf286d8 100644 --- a/lib/Pear/LocalLoop/Controller/Root.pm +++ b/lib/Pear/LocalLoop/Controller/Root.pm @@ -9,7 +9,7 @@ sub index { # if ( $c->is_user_authenticated ) { # $c->redirect_to('/home'); # } - + return 1; } @@ -32,7 +32,7 @@ sub auth_login { else { $c->redirect_to('/'); } - + return 1; } @@ -41,13 +41,13 @@ sub auth_logout { $c->logout; $c->redirect_to('/'); - + return 1; } sub home { my $c = shift; - + return 1; } diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm index e44be58..22438b8 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Postcodes.pm @@ -24,7 +24,7 @@ sub import_csv { while ( my $row = $self->get_csv_line ) { $self->_row_to_result($row); } - + return 1; } @@ -47,7 +47,7 @@ sub _row_to_result { return if $postcode_r->ward; $postcode_r->update( { ward_id => $ward->id } ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm index d0df5c6..7e3dcd5 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Suppliers.pm @@ -22,7 +22,7 @@ sub import_csv { while ( my $row = $self->get_csv_line ) { $self->_row_to_result($row); } - + return 1; } @@ -34,7 +34,8 @@ sub _row_to_result { my $address = ( defined $addr2 ? ( $row->{"address line 2"} . ' ' . $addr2 ) - : $row->{"address line 2"} ); + : $row->{"address line 2"} + ); return if $self->external_result->organisations->find( @@ -58,7 +59,7 @@ sub _row_to_result { } } ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm b/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm index c711a8b..4ad3616 100644 --- a/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm +++ b/lib/Pear/LocalLoop/Import/LCCCsv/Transactions.pm @@ -46,7 +46,7 @@ sub import_csv { while ( my $row = $self->get_csv_line ) { $self->_row_to_result( $row, $lcc_org ); } - + return 1; } @@ -183,7 +183,7 @@ sub _row_to_result { ), } ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm b/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm index b69cad3..f8e9917 100644 --- a/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm +++ b/lib/Pear/LocalLoop/Plugin/BootstrapPagination.pm @@ -99,11 +99,15 @@ sub register { if ( $number eq ".." && $last_num < $actual ) { my $offset = ceil( ( $actual - $round ) / 2 ) + 1; $html .= "url_with->query( [ $param => $start == 0 ? $offset + 1 : $offset ] ) @@ -115,11 +119,15 @@ sub register { my $forw = $round + $actual; my $offset = ceil( ( ( $back - $forw ) / 2 ) + $forw ); $html .= "url_with->query( [ $param => $start == 0 ? $offset + 1 : $offset ] ) @@ -131,18 +139,23 @@ sub register { "
  • $show_number
  • "; + : "" + ) . ">$show_number"; } else { $html .= "url_with->query( [ $param => $number ] ) . $query @@ -176,7 +189,7 @@ sub register { return b($html); } ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/Currency.pm b/lib/Pear/LocalLoop/Plugin/Currency.pm index 287b7ae..9dd2466 100644 --- a/lib/Pear/LocalLoop/Plugin/Currency.pm +++ b/lib/Pear/LocalLoop/Plugin/Currency.pm @@ -24,7 +24,7 @@ sub register { return sprintf( '£%.2f', $value / 100000 ); } ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/Minion.pm b/lib/Pear/LocalLoop/Plugin/Minion.pm index b4edba7..e706485 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion.pm @@ -34,7 +34,7 @@ sub register { else { $app->log->debug('No Minion Config'); } - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm index e1e491c..b79d2df 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_postcode_import.pm @@ -10,7 +10,7 @@ sub run { csv_file => $filename, schema => $self->app->schema )->import_csv; - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm index d051b14..69dee82 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_supplier_import.pm @@ -10,7 +10,7 @@ sub run { csv_file => $filename, schema => $self->app->schema )->import_csv; - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm index 8ec0841..41a8af2 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/csv_transaction_import.pm @@ -11,7 +11,7 @@ sub run { schema => $self->app->schema, target_entity_id => $entity_id, )->import_csv; - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm index 48f6a20..183835c 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/entity_postcode_lookup.pm @@ -30,7 +30,7 @@ sub run { } } } - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm index 5046aa3..aa08259 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/leaderboards_recalc.pm @@ -7,7 +7,7 @@ sub run { my $leaderboard_rs = $self->app->schema->resultset('Leaderboard'); $leaderboard_rs->recalculate_all; - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm b/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm index 6fd0230..10413ea 100644 --- a/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm +++ b/lib/Pear/LocalLoop/Plugin/Minion/Job/test.pm @@ -8,7 +8,7 @@ sub run { for my $arg (@args) { $self->job->app->log->debug($arg); } - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/Postcodes.pm b/lib/Pear/LocalLoop/Plugin/Postcodes.pm index 60e8ddf..b0bc59a 100644 --- a/lib/Pear/LocalLoop/Plugin/Postcodes.pm +++ b/lib/Pear/LocalLoop/Plugin/Postcodes.pm @@ -71,7 +71,7 @@ sub register { return; } ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm b/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm index b540f0d..0c1a539 100644 --- a/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm +++ b/lib/Pear/LocalLoop/Plugin/TemplateHelpers.pm @@ -15,7 +15,7 @@ sub register { } } ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Plugin/Validators.pm b/lib/Pear/LocalLoop/Plugin/Validators.pm index 6acb616..a2ffcc7 100644 --- a/lib/Pear/LocalLoop/Plugin/Validators.pm +++ b/lib/Pear/LocalLoop/Plugin/Validators.pm @@ -101,7 +101,7 @@ sub register { ); $app->helper( validation_error => sub { _validation_error(@_) } ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm index 4de3d20..4af5f06 100644 --- a/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/EntityAssociation.pm @@ -34,5 +34,5 @@ __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( "entity", "Pear::LocalLoop::Schema::Result::Entity", "entity_id", ); - + 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm index a9be49e..c52ad50 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm @@ -146,7 +146,7 @@ sub sqlt_deploy_hook { else { $pending_field->{default_value} = \"false"; } - + return 1; } diff --git a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm index 5e96089..00f6e79 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm @@ -103,7 +103,7 @@ sub sqlt_deploy_hook { else { $pending_field->{default_value} = \"false"; } - + return 1; } diff --git a/lib/Pear/LocalLoop/Schema/Result/User.pm b/lib/Pear/LocalLoop/Schema/Result/User.pm index 4340470..0ac7615 100644 --- a/lib/Pear/LocalLoop/Schema/Result/User.pm +++ b/lib/Pear/LocalLoop/Schema/Result/User.pm @@ -99,7 +99,7 @@ sub sqlt_deploy_hook { else { $pending_field->{default_value} = \"false"; } - + return 1; } diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Category.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Category.pm index 0020c6c..ef74e08 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Category.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Category.pm @@ -8,12 +8,8 @@ use base 'DBIx::Class::ResultSet'; sub as_hash { my ($self) = @_; - my %category_list = ( - ( - map { $_->id => $_->name, } $self->all - ), - 0 => 'Uncategorised', - ); + my %category_list = + ( ( map { $_->id => $_->name, } $self->all ), 0 => 'Uncategorised', ); return \%category_list; } @@ -21,9 +17,7 @@ sub as_hash_name_icon { my ($self) = @_; my %category_list = ( - ( - map { $_->name => $_->line_icon, } $self->all - ), + ( map { $_->name => $_->line_icon, } $self->all ), 0 => 'Uncategorised', ); return \%category_list; diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm b/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm index 186425e..ef0a8dd 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/ImportSet.pm @@ -39,7 +39,7 @@ sub _unordered_get_values { } sub get_users { - my ($self, $set_id) = @_; + my ( $self, $set_id ) = @_; return $self->_unordered_get_values($set_id)->search( {}, diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm index fdb794b..70257e3 100644 --- a/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Leaderboard.pm @@ -92,7 +92,7 @@ sub recalculate_all { warn "Unrecognised Set"; } } - + return 1; } @@ -107,7 +107,7 @@ sub _recalculate_leaderboard { $lb_result->create_new($date); } ); - + return 1; } diff --git a/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm b/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm index 11b332a..33c298a 100644 --- a/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm +++ b/lib/Pear/LocalLoop/Schema/Script/DeploymentHandler.pm @@ -207,7 +207,7 @@ sub cmd_write_ddl { } ); } - + return 1; } @@ -227,7 +227,7 @@ sub cmd_install_dh { version => $self->version, } ); - + return 1; } @@ -245,7 +245,7 @@ sub cmd_install { version => $self->version, } ); - + return 1; } @@ -259,7 +259,7 @@ sub cmd_upgrade { my ($self) = @_; $self->dh->upgrade; - + return 1; } diff --git a/lib/Test/Pear/LocalLoop.pm b/lib/Test/Pear/LocalLoop.pm index 5119cfb..ef9c323 100644 --- a/lib/Test/Pear/LocalLoop.pm +++ b/lib/Test/Pear/LocalLoop.pm @@ -14,7 +14,7 @@ sub BUILD { or die "you need Test::PostgreSQL to run PG testing"; Test::PostgreSQL->import; } - + return 1; } @@ -25,7 +25,7 @@ sub DEMOLISH { $self->mojo->app->schema->storage->dbh->disconnect; $self->pg->stop; } - + return 1; } @@ -145,7 +145,7 @@ sub register_customer { $self->framework->post_ok( '/api/register' => json => $json ) ->status_is(200)->or( $self->dump_error ) ->json_is( '/success', Mojo::JSON->true )->or( $self->dump_error ); - + return 1; } @@ -157,7 +157,7 @@ sub register_organisation { $self->framework->post_ok( '/api/register' => json => $args ) ->status_is(200)->or( $self->dump_error ) ->json_is( '/success', Mojo::JSON->true )->or( $self->dump_error ); - + return 1; } @@ -180,7 +180,7 @@ sub logout { '/api/logout' => json => { session_key => $session_key } ) ->status_is(200)->json_is( '/success', Mojo::JSON->true ) ->json_like( '/message', qr/Logged Out/ ); - + return 1; } @@ -251,7 +251,7 @@ sub install_fixtures { } ); } - + return 1; } From f8598c5bda033a83e9adaaa6718ada85d82adab2 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 23:28:20 +0000 Subject: [PATCH 275/289] Wrap lines --- README.md | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5cee2b7..2dc48dc 100644 --- a/README.md +++ b/README.md @@ -65,12 +65,14 @@ This server app. provides: --with-feature=sqlite \ --with-feature=codepoint-open ``` - - if you are using a PostgreSQL database, replace `--with-feature=sqlite` with `--with-feature=postgres`. + - if you are using a PostgreSQL database, replace `--with-feature=sqlite` + with `--with-feature=postgres`. 1. install the database: - run `./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db'`; - development supports both SQLite and PostgreSQL (production uses PostgreSQL); - for this example we will use SQLite; so - - as the default config. is set up for this, no configuration changes are needed initially. + - as the default config. is set up for this, no configuration changes are + needed initially. 1. set up the development users: - `./script/pear-local_loop dev_data --force` - **DO NOT RUN ON PROD!** @@ -98,14 +100,18 @@ This server app. provides: App. configuration settings are found in `pear-local_loop.⟨environment⟩.conf`. -[Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/) (FCM) credentials should be placed in a file called `localspend-47012.json` in root. This file is not tracked by Git; ask another developer for a copy. +[Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/) +(FCM) credentials should be placed in a file called `localspend-47012.json` in +root. This file is not tracked by Git; ask another developer for a copy. Default user credentials are found in `lib/Pear/LocalLoop/Command/dev_data.pm`. ## Usage -- Run `./script/pear-local_loop minion worker` to start the Minion asynchronous job scheduler; and -- run `morbo script/pear-local_loop -l http://*:3000` to start the server on the specific hostname and port. +- Run `./script/pear-local_loop minion worker` to start the Minion asynchronous + job scheduler; and +- run `morbo script/pear-local_loop -l http://*:3000` to start the server on + the specific hostname and port. ### Database Scripts @@ -119,8 +125,11 @@ Run `./script/pear-local_loop recalc_leaderboards` to update the leaderboards. ## Testing -- Run `prove -lr -j 9` to run the full test suite using [Test-Simple](https://metacpan.org/release/Test-Simple) (when using an SQLite database); and -- run `PEAR_TEST_PG=1 prove -lr -j 9` to run the full test suite (when using a PostgreSQL database). +- Run `prove -lr -j 9` to run the full test suite using + [Test-Simple](https://metacpan.org/release/Test-Simple) (when using an SQLite + database); and +- run `PEAR_TEST_PG=1 prove -lr -j 9` to run the full test suite (when using a + PostgreSQL database). Test files are found in the `t/` directory. @@ -138,7 +147,9 @@ TODO ## Acknowledgements -LocalLoop is the result of collaboration between the [Small Green Consultancy](http://www.smallgreenconsultancy.co.uk/), [Shadowcat Systems](https://shadow.cat/), [Independent Lancaster](http://www.independent-lancaster.co.uk/) and the [Ethical Small Traders Association](http://www.lancasteresta.org/). +LocalLoop is the result of collaboration between the [Small Green Consultancy](http://www.smallgreenconsultancy.co.uk/), +Shadowcat Systems](https://shadow.cat/), [Independent Lancaster](http://www.independent-lancaster.co.uk/) +and the [Ethical Small Traders Association](http://www.lancasteresta.org/). ## License From 3f43c3582d8434ba12feab1c189d891a02f27110 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sat, 20 Mar 2021 23:30:46 +0000 Subject: [PATCH 276/289] Delete debug print --- lib/Pear/LocalLoop/Controller/Api/Auth.pm | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Auth.pm b/lib/Pear/LocalLoop/Controller/Api/Auth.pm index a40d6a7..2926a7f 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Auth.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Auth.pm @@ -124,8 +124,6 @@ sub post_login { sub post_logout { my $c = shift; - print STDERR "TEST"; - my $session_key = $c->req->json('/session_key'); my $session_result = From 196625f839e77b313bfcf851b405500425ad1243 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sun, 21 Mar 2021 12:37:52 +0000 Subject: [PATCH 277/289] Test --- lib/Pear/LocalLoop/Command/codepoint_open.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Pear/LocalLoop/Command/codepoint_open.pm b/lib/Pear/LocalLoop/Command/codepoint_open.pm index adcaf0e..9b83b2c 100644 --- a/lib/Pear/LocalLoop/Command/codepoint_open.pm +++ b/lib/Pear/LocalLoop/Command/codepoint_open.pm @@ -30,6 +30,8 @@ sub run { die; } } + + # foo my $cpo = Geo::UK::Postcode::CodePointOpen->new( path => $output_dir ); From c03ec9ff80f64f1d5b95cd19dfcd02f529370bb5 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sun, 21 Mar 2021 12:40:01 +0000 Subject: [PATCH 278/289] Undo test --- lib/Pear/LocalLoop/Command/codepoint_open.pm | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/Pear/LocalLoop/Command/codepoint_open.pm b/lib/Pear/LocalLoop/Command/codepoint_open.pm index 9b83b2c..adcaf0e 100644 --- a/lib/Pear/LocalLoop/Command/codepoint_open.pm +++ b/lib/Pear/LocalLoop/Command/codepoint_open.pm @@ -30,8 +30,6 @@ sub run { die; } } - - # foo my $cpo = Geo::UK::Postcode::CodePointOpen->new( path => $output_dir ); From b6cc57522d04d2402c8eeaf324d1b9c3b1620fc9 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sun, 21 Mar 2021 12:58:48 +0000 Subject: [PATCH 279/289] Test --- lib/Pear/LocalLoop/Command/codepoint_open.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Pear/LocalLoop/Command/codepoint_open.pm b/lib/Pear/LocalLoop/Command/codepoint_open.pm index adcaf0e..9b83b2c 100644 --- a/lib/Pear/LocalLoop/Command/codepoint_open.pm +++ b/lib/Pear/LocalLoop/Command/codepoint_open.pm @@ -30,6 +30,8 @@ sub run { die; } } + + # foo my $cpo = Geo::UK::Postcode::CodePointOpen->new( path => $output_dir ); From 74c41d9f2bc5e8c1624044a5ccee6fe6c635e80b Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sun, 21 Mar 2021 13:03:13 +0000 Subject: [PATCH 280/289] Test --- lib/Pear/LocalLoop/Command/codepoint_open.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Command/codepoint_open.pm b/lib/Pear/LocalLoop/Command/codepoint_open.pm index 9b83b2c..d0faeb9 100644 --- a/lib/Pear/LocalLoop/Command/codepoint_open.pm +++ b/lib/Pear/LocalLoop/Command/codepoint_open.pm @@ -31,7 +31,7 @@ sub run { } } - # foo + # my $cpo = Geo::UK::Postcode::CodePointOpen->new( path => $output_dir ); From 423184cc29ad70e0bfe92d0657f4035d7055e263 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sun, 21 Mar 2021 13:04:01 +0000 Subject: [PATCH 281/289] Add perl-tidy instructions! --- README.md | 6 ++++-- lib/Pear/LocalLoop/Command/codepoint_open.pm | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2dc48dc..7ffd1d4 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ This server app. provides: - ```shell script ./script/pear-local_loop minion job \ --enqueue 'csv_postcode_import' \ - --args '[ "⟨ path to CSV ⟩ ]' + --args '[ "⟨ path to CSV ⟩" ]' ``` 1. set up postcodes: 1. import [Code-Point Open](https://www.ordnancesurvey.co.uk/business-government/products/code-point-open): @@ -137,7 +137,9 @@ Test files are found in the `t/` directory. Run `for f in ./lib/**/*.pm; do perltidy -b $f; done` to format all Perl files with [Perl-Tidy](https://metacpan.org/release/Perl-Tidy) (there is no built-in -option to format files recursively). +option to format files recursively). This will produce backup files with `.bak` +extensions, so run `rm -r *.bak` to clean up your local copy if you are happy +with the formatted files. Run `perlcritic lib` to lint all Perl files with [Perl-Critic](https://metacpan.org/release/Perl-Critic). diff --git a/lib/Pear/LocalLoop/Command/codepoint_open.pm b/lib/Pear/LocalLoop/Command/codepoint_open.pm index d0faeb9..adcaf0e 100644 --- a/lib/Pear/LocalLoop/Command/codepoint_open.pm +++ b/lib/Pear/LocalLoop/Command/codepoint_open.pm @@ -30,8 +30,6 @@ sub run { die; } } - - # my $cpo = Geo::UK::Postcode::CodePointOpen->new( path => $output_dir ); From abcf16497fde380818189d7b92e75b64845e200d Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sun, 21 Mar 2021 14:47:13 +0000 Subject: [PATCH 282/289] Add server install helper --- install-server.sh | 64 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100755 install-server.sh diff --git a/install-server.sh b/install-server.sh new file mode 100755 index 0000000..606a4dc --- /dev/null +++ b/install-server.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +# This script handles the installation of the server and its dependencies, +# including setting up development data. DO NOT RUN ON PROD. + +echo "Welcome to the LocalLoop server installation helper!" +echo "====================================================" + +read -p "This script will force the installation of development data into the database. \ + For obvious reasons, you *don't* want to do this on prod.\n \ + Did you mean to run this command? (Y/N): " CONFIRM && \ + [[ $CONFIRM == [yY] || $CONFIRM == [yY][eE][sS] ]] || exit 1 + +DATABASE="sqlite" +if [[ $1 == "-p" ]]; then + echo "Using PostgreSQL database..."; + DATABASE="postgres" +fi + +echo "Installing Perl dependencies..." +cpanm --installdeps . \ + --with-feature=$DATABASE \ + --with-feature=codepoint-open +echo "Dependency installation complete." + +if [[ $1 == "-p" ]]; then + echo "This script can only automate deployment for an SQLite database. You \ + will have to sort out your config manually." +else + echo "Deploying dev database and generating dev data..." + ./script/deploy_db install -c 'dbi:SQLite:dbname=foodloop.db' + ./script/pear-local_loop dev_data --force + echo "Database set-up complete." +fi + +while [ $CONFIRM != [yY] || $CONFIRM != [yY][eE][sS] ]; do + unset $CONFIRM + read -p "You must download postcode CSVs manually from \ + \`https://www.doogal.co.uk/PostcodeDownloads.php\`.\n \ + Once you have done so, place them into the `postcode-data/` directory. + Are you ready to continue? (Y/N): " CONFIRM +done + +echo "Importing postcode data..." + +./script/pear-local_loop minion worker +for f in ./postcode-data/*.csv; do + ./script/pear-local_loop minion job \ + --enqueue 'csv_postcode_import' \ + --args '[ \"./postcode-data/$f\" ]' +done + +while [ $CONFIRM != [yY] || $CONFIRM != [yY][eE][sS] ]; do + unset $CONFIRM + read -p "You must manually import all outcodes that you wish to use using \ + the command \`./script/pear-local_loop codepoint_open --outcodes ⟨ outcode(s) ⟩\`. \ + Are you ready to continue? (Y/N): " CONFIRM +done + +./script/pear-local_loop minion job \ + --enqueue entity_postcode_lookup +echo "Postcode data import complete." + +echo "Note: Minion is still running" From 13188d49a1e9bcda9119bbfa7d211a861d348700 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sun, 21 Mar 2021 16:34:08 +0000 Subject: [PATCH 283/289] Add topic creation --- lib/Pear/LocalLoop.pm | 15 +- lib/Pear/LocalLoop/Controller/Api/Devices.pm | 6 +- .../LocalLoop/Controller/Api/Sendmessage.pm | 25 - lib/Pear/LocalLoop/Controller/Api/Topic.pm | 78 + lib/Pear/LocalLoop/Schema.pm | 2 +- .../LocalLoop/Schema/Result/Organisation.pm | 7 + lib/Pear/LocalLoop/Schema/Result/Topic.pm | 12 + .../deploy/34/001-auto-__VERSION.sql | 18 + share/ddl/PostgreSQL/deploy/34/001-auto.sql | 754 ++++ .../ddl/PostgreSQL/upgrade/33-34/001-auto.sql | 19 + .../SQLite/deploy/34/001-auto-__VERSION.sql | 18 + share/ddl/SQLite/deploy/34/001-auto.sql | 503 +++ share/ddl/SQLite/upgrade/33-34/001-auto.sql | 17 + .../_source/deploy/34/001-auto-__VERSION.yml | 91 + share/ddl/_source/deploy/34/001-auto.yml | 3785 +++++++++++++++++ 15 files changed, 5315 insertions(+), 35 deletions(-) create mode 100644 lib/Pear/LocalLoop/Controller/Api/Topic.pm create mode 100644 share/ddl/PostgreSQL/deploy/34/001-auto-__VERSION.sql create mode 100644 share/ddl/PostgreSQL/deploy/34/001-auto.sql create mode 100644 share/ddl/PostgreSQL/upgrade/33-34/001-auto.sql create mode 100644 share/ddl/SQLite/deploy/34/001-auto-__VERSION.sql create mode 100644 share/ddl/SQLite/deploy/34/001-auto.sql create mode 100644 share/ddl/SQLite/upgrade/33-34/001-auto.sql create mode 100644 share/ddl/_source/deploy/34/001-auto-__VERSION.yml create mode 100644 share/ddl/_source/deploy/34/001-auto.yml diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index a58e075..38cc699 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -174,12 +174,6 @@ sub startup { $api_public->post('/logout')->to('api-auth#post_logout'); $api_public->post('/feedback')->to('api-feedback#post_feedback'); - $api_public->post('/check-device-token')->to('api-devices#check_token'); - $api_public->post('/add-device-token')->to('api-devices#add_token'); - $api_public->post('/get-topics')->to('api-sendmessage#get_topics'); - $api_public->post('/get-device-tokens')->to('api-devices#get_tokens'); - $api_public->post('/send-message')->to('api-sendmessage#post_message'); - # Private, must be authenticated api routes my $api = $api_public->under('/')->to('api-auth#auth'); @@ -212,6 +206,15 @@ sub startup { ->to('api-transactions#update_recurring'); $api->post('/recurring-transactions/delete') ->to('api-transactions#delete_recurring'); + + $api->post('/device-token/check')->to('api-devices#check_exists'); + $api->post('/device-token/add')->to('api-devices#create'); + $api->post('/device-tokens')->to('api-devices#get_all'); + + $api->post('/topic/add')->to('api-topic#create'); + $api->post('/topics')->to('api-topic#get_all'); + + $api->post('/send-message')->to('api-sendmessage#post_message'); my $api_v1 = $api->under('/v1'); diff --git a/lib/Pear/LocalLoop/Controller/Api/Devices.pm b/lib/Pear/LocalLoop/Controller/Api/Devices.pm index 7c91143..c483b1f 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Devices.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Devices.pm @@ -19,7 +19,7 @@ has error_messages => sub { }; }; -sub check_token { +sub check_exists { my $c = shift; my $validation = $c->validation; @@ -47,7 +47,7 @@ sub check_token { } } -sub add_token { +sub create { my $c = shift; my $validation = $c->validation; @@ -120,7 +120,7 @@ sub add_token { } } -sub get_tokens { +sub get_all { my $c = shift; my $token_rs = $c->schema->resultset('DeviceToken'); diff --git a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm index 3cbee6a..9ba71a7 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Sendmessage.pm @@ -65,31 +65,6 @@ sub create_jwt_from_path_and_scopes { return $jwt->encode; } -sub get_topics { - my $c = shift; - - my $topic_rs = $c->schema->resultset('Topic'); - - my @topics = ( - map { - { - id => $_->id, - name => $_->name, - numberOfSubscribers => - $_->search_related( 'device_subscriptions', - { 'topic_id' => $_->id } )->count, - } - } $topic_rs->all - ); - - return $c->render( - json => { - success => Mojo::JSON->true, - topics => \@topics, - } - ); -} - sub post_message { my $c = shift; diff --git a/lib/Pear/LocalLoop/Controller/Api/Topic.pm b/lib/Pear/LocalLoop/Controller/Api/Topic.pm new file mode 100644 index 0000000..9bf7201 --- /dev/null +++ b/lib/Pear/LocalLoop/Controller/Api/Topic.pm @@ -0,0 +1,78 @@ +package Pear::LocalLoop::Controller::Api::Topic; +use Mojo::Base 'Mojolicious::Controller'; +use LWP::UserAgent; +use JSON; +use JSON::Parse 'parse_json'; +use Mojo::JWT; +use Mojo::File; +use Carp; + +has error_messages => sub { + return { + topic => { + required => { message => 'Topic is required', status => 400 }, + not_in_resultset => { message => 'Topic already exists', status => 400 }, + } + }; +}; + +sub create { + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + my $topic_rs = $c->schema->resultset('Topic'); + my $user_rs = $c->schema->resultset('User'); + + $validation->required('topic')->not_in_resultset( 'topic', $topic_rs ); + # TODO: validate that requester is an org user + + my $organisation = $user->entity->organisation; + + return $c->api_validation_error if $validation->has_error; + + my $topic = $validation->param('topic'); + + $organisation->create_related( + 'topics', + { + name => $topic, + } + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Topic created successfully!', + } + ); +} + +sub get_all { + my $c = shift; + + my $topic_rs = $c->schema->resultset('Topic'); + + my @topics = ( + map { + { + id => $_->id, + name => $_->name, + numberOfSubscribers => + $_->search_related( 'device_subscriptions', + { 'topic_id' => $_->id } )->count, + } + } $topic_rs->all + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + topics => \@topics, + } + ); +} +1; diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index 7333240..17cb9cf 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -6,7 +6,7 @@ use warnings; use base 'DBIx::Class::Schema'; -our $VERSION = 33; +our $VERSION = 34; __PACKAGE__->load_namespaces; diff --git a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm index c52ad50..d2c4040 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm @@ -124,6 +124,13 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); +__PACKAGE__->has_many( + "topics", + "Pear::LocalLoop::Schema::Result::Topic", + { "foreign.organisation_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + __PACKAGE__->filter_column( pending => { filter_to_storage => 'to_bool', diff --git a/lib/Pear/LocalLoop/Schema/Result/Topic.pm b/lib/Pear/LocalLoop/Schema/Result/Topic.pm index aab2684..434ae62 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Topic.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Topic.pm @@ -21,6 +21,11 @@ __PACKAGE__->add_columns( is_auto_increment => 1, is_nullable => 0, }, + "organisation_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 1, + }, "name" => { data_type => "varchar", size => 200, @@ -30,6 +35,13 @@ __PACKAGE__->add_columns( __PACKAGE__->set_primary_key("id"); +__PACKAGE__->belongs_to( + "organisation", + "Pear::LocalLoop::Schema::Result::Organisation", + { id => "organisation_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, +); + __PACKAGE__->has_many( "device_subscriptions", "Pear::LocalLoop::Schema::Result::DeviceSubscription", diff --git a/share/ddl/PostgreSQL/deploy/34/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/34/001-auto-__VERSION.sql new file mode 100644 index 0000000..336feb7 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/34/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Sun Mar 21 16:21:53 2021 +-- +; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE "dbix_class_deploymenthandler_versions" ( + "id" serial NOT NULL, + "version" character varying(50) NOT NULL, + "ddl" text, + "upgrade_sql" text, + PRIMARY KEY ("id"), + CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version") +); + +; diff --git a/share/ddl/PostgreSQL/deploy/34/001-auto.sql b/share/ddl/PostgreSQL/deploy/34/001-auto.sql new file mode 100644 index 0000000..4d30065 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/34/001-auto.sql @@ -0,0 +1,754 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Sun Mar 21 16:21:52 2021 +-- +; +-- +-- Table: account_tokens +-- +CREATE TABLE "account_tokens" ( + "id" serial NOT NULL, + "name" text NOT NULL, + "used" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "account_tokens_name" UNIQUE ("name") +); + +; +-- +-- Table: category +-- +CREATE TABLE "category" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "line_icon" character varying(255), + PRIMARY KEY ("id"), + CONSTRAINT "category_name" UNIQUE ("name") +); + +; +-- +-- Table: entities +-- +CREATE TABLE "entities" ( + "id" serial NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: external_references +-- +CREATE TABLE "external_references" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "external_references_name" UNIQUE ("name") +); + +; +-- +-- Table: gb_wards +-- +CREATE TABLE "gb_wards" ( + "id" serial NOT NULL, + "ward" character varying(100) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: global_medal_group +-- +CREATE TABLE "global_medal_group" ( + "id" serial NOT NULL, + "group_name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "global_medal_group_group_name" UNIQUE ("group_name") +); + +; +-- +-- Table: import_sets +-- +CREATE TABLE "import_sets" ( + "id" serial NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: leaderboards +-- +CREATE TABLE "leaderboards" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboards_type" UNIQUE ("type") +); + +; +-- +-- Table: org_medal_group +-- +CREATE TABLE "org_medal_group" ( + "id" serial NOT NULL, + "group_name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "org_medal_group_group_name" UNIQUE ("group_name") +); + +; +-- +-- Table: organisation_social_types +-- +CREATE TABLE "organisation_social_types" ( + "id" serial NOT NULL, + "key" character varying(255) NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisation_social_types_key" UNIQUE ("key") +); + +; +-- +-- Table: organisation_types +-- +CREATE TABLE "organisation_types" ( + "id" serial NOT NULL, + "key" character varying(255) NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisation_types_key" UNIQUE ("key") +); + +; +-- +-- Table: customers +-- +CREATE TABLE "customers" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "display_name" character varying(255) NOT NULL, + "full_name" character varying(255) NOT NULL, + "year_of_birth" integer NOT NULL, + "postcode" character varying(16) NOT NULL, + "latitude" numeric(5,2), + "longitude" numeric(5,2), + PRIMARY KEY ("id") +); +CREATE INDEX "customers_idx_entity_id" on "customers" ("entity_id"); + +; +-- +-- Table: entity_association +-- +CREATE TABLE "entity_association" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "lis" boolean, + "esta" boolean, + PRIMARY KEY ("id") +); +CREATE INDEX "entity_association_idx_entity_id" on "entity_association" ("entity_id"); + +; +-- +-- Table: gb_postcodes +-- +CREATE TABLE "gb_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) DEFAULT '' NOT NULL, + "latitude" numeric(7,5), + "longitude" numeric(7,5), + "ward_id" integer, + PRIMARY KEY ("outcode", "incode") +); +CREATE INDEX "gb_postcodes_idx_ward_id" on "gb_postcodes" ("ward_id"); + +; +-- +-- Table: global_medals +-- +CREATE TABLE "global_medals" ( + "id" serial NOT NULL, + "group_id" integer NOT NULL, + "threshold" integer NOT NULL, + "points" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_medals_idx_group_id" on "global_medals" ("group_id"); + +; +-- +-- Table: leaderboard_sets +-- +CREATE TABLE "leaderboard_sets" ( + "id" serial NOT NULL, + "leaderboard_id" integer NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "leaderboard_sets_idx_leaderboard_id" on "leaderboard_sets" ("leaderboard_id"); + +; +-- +-- Table: org_medals +-- +CREATE TABLE "org_medals" ( + "id" serial NOT NULL, + "group_id" integer NOT NULL, + "threshold" integer NOT NULL, + "points" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_medals_idx_group_id" on "org_medals" ("group_id"); + +; +-- +-- Table: transactions +-- +CREATE TABLE "transactions" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "proof_image" text, + "submitted_at" timestamp NOT NULL, + "purchase_time" timestamp NOT NULL, + "essential" boolean DEFAULT false NOT NULL, + "distance" numeric(15), + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_idx_buyer_id" on "transactions" ("buyer_id"); +CREATE INDEX "transactions_idx_seller_id" on "transactions" ("seller_id"); + +; +-- +-- Table: users +-- +CREATE TABLE "users" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "email" text NOT NULL, + "join_date" timestamp NOT NULL, + "password" character varying(100) NOT NULL, + "is_admin" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "users_email" UNIQUE ("email") +); +CREATE INDEX "users_idx_entity_id" on "users" ("entity_id"); + +; +-- +-- Table: device_tokens +-- +CREATE TABLE "device_tokens" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "token" character varying(200) NOT NULL, + "register_date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "device_tokens_idx_user_id" on "device_tokens" ("user_id"); + +; +-- +-- Table: feedback +-- +CREATE TABLE "feedback" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "feedbacktext" text NOT NULL, + "app_name" character varying(255) NOT NULL, + "package_name" character varying(255) NOT NULL, + "version_code" character varying(255) NOT NULL, + "version_number" character varying(255) NOT NULL, + "actioned" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "feedback_idx_user_id" on "feedback" ("user_id"); + +; +-- +-- Table: global_user_medal_progress +-- +CREATE TABLE "global_user_medal_progress" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "total" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_user_medal_progress_idx_entity_id" on "global_user_medal_progress" ("entity_id"); +CREATE INDEX "global_user_medal_progress_idx_group_id" on "global_user_medal_progress" ("group_id"); + +; +-- +-- Table: global_user_medals +-- +CREATE TABLE "global_user_medals" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "points" integer NOT NULL, + "awarded_at" timestamp NOT NULL, + "threshold" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_user_medals_idx_entity_id" on "global_user_medals" ("entity_id"); +CREATE INDEX "global_user_medals_idx_group_id" on "global_user_medals" ("group_id"); + +; +-- +-- Table: import_lookups +-- +CREATE TABLE "import_lookups" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_lookups_idx_entity_id" on "import_lookups" ("entity_id"); +CREATE INDEX "import_lookups_idx_set_id" on "import_lookups" ("set_id"); + +; +-- +-- Table: org_user_medal_progress +-- +CREATE TABLE "org_user_medal_progress" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "total" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_user_medal_progress_idx_entity_id" on "org_user_medal_progress" ("entity_id"); +CREATE INDEX "org_user_medal_progress_idx_group_id" on "org_user_medal_progress" ("group_id"); + +; +-- +-- Table: org_user_medals +-- +CREATE TABLE "org_user_medals" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "points" integer NOT NULL, + "awarded_at" timestamp NOT NULL, + "threshold" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_user_medals_idx_entity_id" on "org_user_medals" ("entity_id"); +CREATE INDEX "org_user_medals_idx_group_id" on "org_user_medals" ("group_id"); + +; +-- +-- Table: session_tokens +-- +CREATE TABLE "session_tokens" ( + "id" serial NOT NULL, + "token" character varying(255) NOT NULL, + "user_id" integer NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "session_tokens_token" UNIQUE ("token") +); +CREATE INDEX "session_tokens_idx_user_id" on "session_tokens" ("user_id"); + +; +-- +-- Table: transaction_recurring +-- +CREATE TABLE "transaction_recurring" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "start_time" timestamp NOT NULL, + "last_updated" timestamp, + "essential" boolean DEFAULT false NOT NULL, + "distance" numeric(15), + "category_id" integer, + "recurring_period" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transaction_recurring_idx_buyer_id" on "transaction_recurring" ("buyer_id"); +CREATE INDEX "transaction_recurring_idx_category_id" on "transaction_recurring" ("category_id"); +CREATE INDEX "transaction_recurring_idx_seller_id" on "transaction_recurring" ("seller_id"); + +; +-- +-- Table: transactions_meta +-- +CREATE TABLE "transactions_meta" ( + "id" serial NOT NULL, + "transaction_id" integer NOT NULL, + "net_value" numeric(100,0) NOT NULL, + "sales_tax_value" numeric(100,0) NOT NULL, + "gross_value" numeric(100,0) NOT NULL, + "local_service" boolean DEFAULT false NOT NULL, + "regional_service" boolean DEFAULT false NOT NULL, + "national_service" boolean DEFAULT false NOT NULL, + "private_household_rebate" boolean DEFAULT false NOT NULL, + "business_tax_and_rebate" boolean DEFAULT false NOT NULL, + "stat_loc_gov" boolean DEFAULT false NOT NULL, + "central_loc_gov" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_meta_idx_transaction_id" on "transactions_meta" ("transaction_id"); + +; +-- +-- Table: entities_postcodes +-- +CREATE TABLE "entities_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("outcode", "incode", "entity_id") +); +CREATE INDEX "entities_postcodes_idx_entity_id" on "entities_postcodes" ("entity_id"); +CREATE INDEX "entities_postcodes_idx_outcode_incode" on "entities_postcodes" ("outcode", "incode"); + +; +-- +-- Table: import_values +-- +CREATE TABLE "import_values" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "user_name" character varying(255) NOT NULL, + "purchase_date" timestamp NOT NULL, + "purchase_value" character varying(255) NOT NULL, + "org_name" character varying(255) NOT NULL, + "transaction_id" integer, + "ignore_value" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_values_idx_set_id" on "import_values" ("set_id"); +CREATE INDEX "import_values_idx_transaction_id" on "import_values" ("transaction_id"); + +; +-- +-- Table: leaderboard_values +-- +CREATE TABLE "leaderboard_values" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "set_id" integer NOT NULL, + "position" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "trend" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboard_values_entity_id_set_id" UNIQUE ("entity_id", "set_id") +); +CREATE INDEX "leaderboard_values_idx_entity_id" on "leaderboard_values" ("entity_id"); +CREATE INDEX "leaderboard_values_idx_set_id" on "leaderboard_values" ("set_id"); + +; +-- +-- Table: organisations +-- +CREATE TABLE "organisations" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "street_name" text, + "town" character varying(255) NOT NULL, + "postcode" character varying(16), + "country" character varying(255), + "sector" character varying(1), + "pending" boolean DEFAULT false NOT NULL, + "is_local" boolean, + "is_fair" boolean, + "submitted_by_id" integer, + "latitude" numeric(8,5), + "longitude" numeric(8,5), + "type_id" integer, + "social_type_id" integer, + "is_anchor" boolean DEFAULT FALSE NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisations_idx_entity_id" on "organisations" ("entity_id"); +CREATE INDEX "organisations_idx_type_id" on "organisations" ("type_id"); +CREATE INDEX "organisations_idx_social_type_id" on "organisations" ("social_type_id"); + +; +-- +-- Table: transaction_category +-- +CREATE TABLE "transaction_category" ( + "category_id" integer NOT NULL, + "transaction_id" integer NOT NULL, + CONSTRAINT "transaction_category_transaction_id" UNIQUE ("transaction_id") +); +CREATE INDEX "transaction_category_idx_category_id" on "transaction_category" ("category_id"); +CREATE INDEX "transaction_category_idx_transaction_id" on "transaction_category" ("transaction_id"); + +; +-- +-- Table: transactions_external +-- +CREATE TABLE "transactions_external" ( + "id" serial NOT NULL, + "transaction_id" integer NOT NULL, + "external_reference_id" integer NOT NULL, + "external_id" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "transactions_external_external_reference_id_external_id" UNIQUE ("external_reference_id", "external_id") +); +CREATE INDEX "transactions_external_idx_external_reference_id" on "transactions_external" ("external_reference_id"); +CREATE INDEX "transactions_external_idx_transaction_id" on "transactions_external" ("transaction_id"); + +; +-- +-- Table: organisation_payroll +-- +CREATE TABLE "organisation_payroll" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "entry_period" timestamp NOT NULL, + "employee_amount" integer NOT NULL, + "local_employee_amount" integer NOT NULL, + "gross_payroll" numeric(100,0) NOT NULL, + "payroll_income_tax" numeric(100,0) NOT NULL, + "payroll_employee_ni" numeric(100,0) NOT NULL, + "payroll_employer_ni" numeric(100,0) NOT NULL, + "payroll_total_pension" numeric(100,0) NOT NULL, + "payroll_other_benefit" numeric(100,0) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisation_payroll_idx_org_id" on "organisation_payroll" ("org_id"); + +; +-- +-- Table: topics +-- +CREATE TABLE "topics" ( + "id" serial NOT NULL, + "organisation_id" integer, + "name" character varying(200) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "topics_idx_organisation_id" on "topics" ("organisation_id"); + +; +-- +-- Table: organisations_external +-- +CREATE TABLE "organisations_external" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "external_reference_id" integer NOT NULL, + "external_id" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisations_external_external_reference_id_external_id" UNIQUE ("external_reference_id", "external_id") +); +CREATE INDEX "organisations_external_idx_external_reference_id" on "organisations_external" ("external_reference_id"); +CREATE INDEX "organisations_external_idx_org_id" on "organisations_external" ("org_id"); + +; +-- +-- Table: device_subscriptions +-- +CREATE TABLE "device_subscriptions" ( + "id" serial NOT NULL, + "device_token_id" integer NOT NULL, + "topic_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "device_subscriptions_idx_device_token_id" on "device_subscriptions" ("device_token_id"); +CREATE INDEX "device_subscriptions_idx_topic_id" on "device_subscriptions" ("topic_id"); + +; +-- +-- Foreign Key Definitions +-- + +; +ALTER TABLE "customers" ADD CONSTRAINT "customers_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entity_association" ADD CONSTRAINT "entity_association_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "gb_postcodes" ADD CONSTRAINT "gb_postcodes_fk_ward_id" FOREIGN KEY ("ward_id") + REFERENCES "gb_wards" ("id") DEFERRABLE; + +; +ALTER TABLE "global_medals" ADD CONSTRAINT "global_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_sets" ADD CONSTRAINT "leaderboard_sets_fk_leaderboard_id" FOREIGN KEY ("leaderboard_id") + REFERENCES "leaderboards" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_medals" ADD CONSTRAINT "org_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "users" ADD CONSTRAINT "users_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "device_tokens" ADD CONSTRAINT "device_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "feedback" ADD CONSTRAINT "feedback_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "global_user_medal_progress" ADD CONSTRAINT "global_user_medal_progress_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "global_user_medal_progress" ADD CONSTRAINT "global_user_medal_progress_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "global_user_medals" ADD CONSTRAINT "global_user_medals_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "global_user_medals" ADD CONSTRAINT "global_user_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_user_medal_progress" ADD CONSTRAINT "org_user_medal_progress_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "org_user_medal_progress" ADD CONSTRAINT "org_user_medal_progress_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_user_medals" ADD CONSTRAINT "org_user_medals_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "org_user_medals" ADD CONSTRAINT "org_user_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "session_tokens" ADD CONSTRAINT "session_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") DEFERRABLE; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions_meta" ADD CONSTRAINT "transactions_meta_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entities_postcodes" ADD CONSTRAINT "entities_postcodes_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entities_postcodes" ADD CONSTRAINT "entities_postcodes_fk_outcode_incode" FOREIGN KEY ("outcode", "incode") + REFERENCES "gb_postcodes" ("outcode", "incode") DEFERRABLE; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "leaderboard_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_type_id" FOREIGN KEY ("type_id") + REFERENCES "organisation_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_social_type_id" FOREIGN KEY ("social_type_id") + REFERENCES "organisation_social_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions_external" ADD CONSTRAINT "transactions_external_fk_external_reference_id" FOREIGN KEY ("external_reference_id") + REFERENCES "external_references" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions_external" ADD CONSTRAINT "transactions_external_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisation_payroll" ADD CONSTRAINT "organisation_payroll_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") DEFERRABLE; + +; +ALTER TABLE "topics" ADD CONSTRAINT "topics_fk_organisation_id" FOREIGN KEY ("organisation_id") + REFERENCES "organisations" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations_external" ADD CONSTRAINT "organisations_external_fk_external_reference_id" FOREIGN KEY ("external_reference_id") + REFERENCES "external_references" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations_external" ADD CONSTRAINT "organisations_external_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "device_subscriptions" ADD CONSTRAINT "device_subscriptions_fk_device_token_id" FOREIGN KEY ("device_token_id") + REFERENCES "device_tokens" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "device_subscriptions" ADD CONSTRAINT "device_subscriptions_fk_topic_id" FOREIGN KEY ("topic_id") + REFERENCES "topics" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; diff --git a/share/ddl/PostgreSQL/upgrade/33-34/001-auto.sql b/share/ddl/PostgreSQL/upgrade/33-34/001-auto.sql new file mode 100644 index 0000000..624d525 --- /dev/null +++ b/share/ddl/PostgreSQL/upgrade/33-34/001-auto.sql @@ -0,0 +1,19 @@ +-- Convert schema 'share/ddl/_source/deploy/33/001-auto.yml' to 'share/ddl/_source/deploy/34/001-auto.yml':; + +; +BEGIN; + +; +ALTER TABLE topics ADD COLUMN organisation_id integer; + +; +CREATE INDEX topics_idx_organisation_id on topics (organisation_id); + +; +ALTER TABLE topics ADD CONSTRAINT topics_fk_organisation_id FOREIGN KEY (organisation_id) + REFERENCES organisations (id) ON DELETE NO ACTION ON UPDATE NO ACTION; + +; + +COMMIT; + diff --git a/share/ddl/SQLite/deploy/34/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/34/001-auto-__VERSION.sql new file mode 100644 index 0000000..77340b0 --- /dev/null +++ b/share/ddl/SQLite/deploy/34/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Sun Mar 21 16:21:53 2021 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE dbix_class_deploymenthandler_versions ( + id INTEGER PRIMARY KEY NOT NULL, + version varchar(50) NOT NULL, + ddl text, + upgrade_sql text +); +CREATE UNIQUE INDEX dbix_class_deploymenthandler_versions_version ON dbix_class_deploymenthandler_versions (version); +COMMIT; diff --git a/share/ddl/SQLite/deploy/34/001-auto.sql b/share/ddl/SQLite/deploy/34/001-auto.sql new file mode 100644 index 0000000..50267b0 --- /dev/null +++ b/share/ddl/SQLite/deploy/34/001-auto.sql @@ -0,0 +1,503 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Sun Mar 21 16:21:53 2021 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: account_tokens +-- +CREATE TABLE account_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + name text NOT NULL, + used integer NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX account_tokens_name ON account_tokens (name); +-- +-- Table: category +-- +CREATE TABLE category ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + line_icon varchar(255) +); +CREATE UNIQUE INDEX category_name ON category (name); +-- +-- Table: entities +-- +CREATE TABLE entities ( + id INTEGER PRIMARY KEY NOT NULL, + type varchar(255) NOT NULL +); +-- +-- Table: external_references +-- +CREATE TABLE external_references ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX external_references_name ON external_references (name); +-- +-- Table: gb_wards +-- +CREATE TABLE gb_wards ( + id INTEGER PRIMARY KEY NOT NULL, + ward varchar(100) NOT NULL +); +-- +-- Table: global_medal_group +-- +CREATE TABLE global_medal_group ( + id INTEGER PRIMARY KEY NOT NULL, + group_name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX global_medal_group_group_name ON global_medal_group (group_name); +-- +-- Table: import_sets +-- +CREATE TABLE import_sets ( + id INTEGER PRIMARY KEY NOT NULL, + date datetime NOT NULL +); +-- +-- Table: leaderboards +-- +CREATE TABLE leaderboards ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + type varchar(255) NOT NULL +); +CREATE UNIQUE INDEX leaderboards_type ON leaderboards (type); +-- +-- Table: org_medal_group +-- +CREATE TABLE org_medal_group ( + id INTEGER PRIMARY KEY NOT NULL, + group_name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX org_medal_group_group_name ON org_medal_group (group_name); +-- +-- Table: organisation_social_types +-- +CREATE TABLE organisation_social_types ( + id INTEGER PRIMARY KEY NOT NULL, + key varchar(255) NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX organisation_social_types_key ON organisation_social_types (key); +-- +-- Table: organisation_types +-- +CREATE TABLE organisation_types ( + id INTEGER PRIMARY KEY NOT NULL, + key varchar(255) NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX organisation_types_key ON organisation_types (key); +-- +-- Table: customers +-- +CREATE TABLE customers ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + display_name varchar(255) NOT NULL, + full_name varchar(255) NOT NULL, + year_of_birth integer NOT NULL, + postcode varchar(16) NOT NULL, + latitude decimal(5,2), + longitude decimal(5,2), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX customers_idx_entity_id ON customers (entity_id); +-- +-- Table: entity_association +-- +CREATE TABLE entity_association ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + lis boolean, + esta boolean, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX entity_association_idx_entity_id ON entity_association (entity_id); +-- +-- Table: gb_postcodes +-- +CREATE TABLE gb_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL DEFAULT '', + latitude decimal(7,5), + longitude decimal(7,5), + ward_id integer, + PRIMARY KEY (outcode, incode), + FOREIGN KEY (ward_id) REFERENCES gb_wards(id) +); +CREATE INDEX gb_postcodes_idx_ward_id ON gb_postcodes (ward_id); +-- +-- Table: global_medals +-- +CREATE TABLE global_medals ( + id INTEGER PRIMARY KEY NOT NULL, + group_id integer NOT NULL, + threshold integer NOT NULL, + points integer NOT NULL, + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_medals_idx_group_id ON global_medals (group_id); +-- +-- Table: leaderboard_sets +-- +CREATE TABLE leaderboard_sets ( + id INTEGER PRIMARY KEY NOT NULL, + leaderboard_id integer NOT NULL, + date datetime NOT NULL, + FOREIGN KEY (leaderboard_id) REFERENCES leaderboards(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_sets_idx_leaderboard_id ON leaderboard_sets (leaderboard_id); +-- +-- Table: org_medals +-- +CREATE TABLE org_medals ( + id INTEGER PRIMARY KEY NOT NULL, + group_id integer NOT NULL, + threshold integer NOT NULL, + points integer NOT NULL, + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_medals_idx_group_id ON org_medals (group_id); +-- +-- Table: transactions +-- +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + essential boolean NOT NULL DEFAULT false, + distance numeric(15), + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transactions_idx_buyer_id ON transactions (buyer_id); +CREATE INDEX transactions_idx_seller_id ON transactions (seller_id); +-- +-- Table: users +-- +CREATE TABLE users ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + email text NOT NULL, + join_date datetime NOT NULL, + password varchar(100) NOT NULL, + is_admin boolean NOT NULL DEFAULT false, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX users_idx_entity_id ON users (entity_id); +CREATE UNIQUE INDEX users_email ON users (email); +-- +-- Table: device_tokens +-- +CREATE TABLE device_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + token varchar(200) NOT NULL, + register_date datetime NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX device_tokens_idx_user_id ON device_tokens (user_id); +-- +-- Table: feedback +-- +CREATE TABLE feedback ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + submitted_at datetime NOT NULL, + feedbacktext text NOT NULL, + app_name varchar(255) NOT NULL, + package_name varchar(255) NOT NULL, + version_code varchar(255) NOT NULL, + version_number varchar(255) NOT NULL, + actioned boolean NOT NULL DEFAULT false, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX feedback_idx_user_id ON feedback (user_id); +-- +-- Table: global_user_medal_progress +-- +CREATE TABLE global_user_medal_progress ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + total integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_user_medal_progress_idx_entity_id ON global_user_medal_progress (entity_id); +CREATE INDEX global_user_medal_progress_idx_group_id ON global_user_medal_progress (group_id); +-- +-- Table: global_user_medals +-- +CREATE TABLE global_user_medals ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + points integer NOT NULL, + awarded_at datetime NOT NULL, + threshold integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_user_medals_idx_entity_id ON global_user_medals (entity_id); +CREATE INDEX global_user_medals_idx_group_id ON global_user_medals (group_id); +-- +-- Table: import_lookups +-- +CREATE TABLE import_lookups ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + name varchar(255) NOT NULL, + entity_id integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_lookups_idx_entity_id ON import_lookups (entity_id); +CREATE INDEX import_lookups_idx_set_id ON import_lookups (set_id); +-- +-- Table: org_user_medal_progress +-- +CREATE TABLE org_user_medal_progress ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + total integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_user_medal_progress_idx_entity_id ON org_user_medal_progress (entity_id); +CREATE INDEX org_user_medal_progress_idx_group_id ON org_user_medal_progress (group_id); +-- +-- Table: org_user_medals +-- +CREATE TABLE org_user_medals ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + points integer NOT NULL, + awarded_at datetime NOT NULL, + threshold integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_user_medals_idx_entity_id ON org_user_medals (entity_id); +CREATE INDEX org_user_medals_idx_group_id ON org_user_medals (group_id); +-- +-- Table: session_tokens +-- +CREATE TABLE session_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + token varchar(255) NOT NULL, + user_id integer NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX session_tokens_idx_user_id ON session_tokens (user_id); +CREATE UNIQUE INDEX session_tokens_token ON session_tokens (token); +-- +-- Table: transaction_recurring +-- +CREATE TABLE transaction_recurring ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + start_time datetime NOT NULL, + last_updated datetime, + essential boolean NOT NULL DEFAULT false, + distance numeric(15), + category_id integer, + recurring_period varchar(255) NOT NULL, + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (category_id) REFERENCES category(id), + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transaction_recurring_idx_buyer_id ON transaction_recurring (buyer_id); +CREATE INDEX transaction_recurring_idx_category_id ON transaction_recurring (category_id); +CREATE INDEX transaction_recurring_idx_seller_id ON transaction_recurring (seller_id); +-- +-- Table: transactions_meta +-- +CREATE TABLE transactions_meta ( + id INTEGER PRIMARY KEY NOT NULL, + transaction_id integer NOT NULL, + net_value numeric(100,0) NOT NULL, + sales_tax_value numeric(100,0) NOT NULL, + gross_value numeric(100,0) NOT NULL, + local_service boolean NOT NULL DEFAULT false, + regional_service boolean NOT NULL DEFAULT false, + national_service boolean NOT NULL DEFAULT false, + private_household_rebate boolean NOT NULL DEFAULT false, + business_tax_and_rebate boolean NOT NULL DEFAULT false, + stat_loc_gov boolean NOT NULL DEFAULT false, + central_loc_gov boolean NOT NULL DEFAULT false, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); +CREATE INDEX transactions_meta_idx_transaction_id ON transactions_meta (transaction_id); +-- +-- Table: entities_postcodes +-- +CREATE TABLE entities_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL, + entity_id integer NOT NULL, + PRIMARY KEY (outcode, incode, entity_id), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE, + FOREIGN KEY (outcode, incode) REFERENCES gb_postcodes(outcode, incode) +); +CREATE INDEX entities_postcodes_idx_entity_id ON entities_postcodes (entity_id); +CREATE INDEX entities_postcodes_idx_outcode_incode ON entities_postcodes (outcode, incode); +-- +-- Table: import_values +-- +CREATE TABLE import_values ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + user_name varchar(255) NOT NULL, + purchase_date datetime NOT NULL, + purchase_value varchar(255) NOT NULL, + org_name varchar(255) NOT NULL, + transaction_id integer, + ignore_value boolean NOT NULL DEFAULT false, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_values_idx_set_id ON import_values (set_id); +CREATE INDEX import_values_idx_transaction_id ON import_values (transaction_id); +-- +-- Table: leaderboard_values +-- +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_values_idx_entity_id ON leaderboard_values (entity_id); +CREATE INDEX leaderboard_values_idx_set_id ON leaderboard_values (set_id); +CREATE UNIQUE INDEX leaderboard_values_entity_id_set_id ON leaderboard_values (entity_id, set_id); +-- +-- Table: organisations +-- +CREATE TABLE organisations ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + name varchar(255) NOT NULL, + street_name text, + town varchar(255) NOT NULL, + postcode varchar(16), + country varchar(255), + sector varchar(1), + pending boolean NOT NULL DEFAULT false, + is_local boolean, + is_fair boolean, + submitted_by_id integer, + latitude decimal(8,5), + longitude decimal(8,5), + type_id integer, + social_type_id integer, + is_anchor boolean NOT NULL DEFAULT FALSE, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE, + FOREIGN KEY (type_id) REFERENCES organisation_types(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (social_type_id) REFERENCES organisation_social_types(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX organisations_idx_entity_id ON organisations (entity_id); +CREATE INDEX organisations_idx_type_id ON organisations (type_id); +CREATE INDEX organisations_idx_social_type_id ON organisations (social_type_id); +-- +-- Table: transaction_category +-- +CREATE TABLE transaction_category ( + category_id integer NOT NULL, + transaction_id integer NOT NULL, + FOREIGN KEY (category_id) REFERENCES category(id) ON DELETE CASCADE, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); +CREATE INDEX transaction_category_idx_category_id ON transaction_category (category_id); +CREATE INDEX transaction_category_idx_transaction_id ON transaction_category (transaction_id); +CREATE UNIQUE INDEX transaction_category_transaction_id ON transaction_category (transaction_id); +-- +-- Table: transactions_external +-- +CREATE TABLE transactions_external ( + id INTEGER PRIMARY KEY NOT NULL, + transaction_id integer NOT NULL, + external_reference_id integer NOT NULL, + external_id varchar(255) NOT NULL, + FOREIGN KEY (external_reference_id) REFERENCES external_references(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX transactions_external_idx_external_reference_id ON transactions_external (external_reference_id); +CREATE INDEX transactions_external_idx_transaction_id ON transactions_external (transaction_id); +CREATE UNIQUE INDEX transactions_external_external_reference_id_external_id ON transactions_external (external_reference_id, external_id); +-- +-- Table: organisation_payroll +-- +CREATE TABLE organisation_payroll ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + submitted_at datetime NOT NULL, + entry_period datetime NOT NULL, + employee_amount integer NOT NULL, + local_employee_amount integer NOT NULL, + gross_payroll numeric(100,0) NOT NULL, + payroll_income_tax numeric(100,0) NOT NULL, + payroll_employee_ni numeric(100,0) NOT NULL, + payroll_employer_ni numeric(100,0) NOT NULL, + payroll_total_pension numeric(100,0) NOT NULL, + payroll_other_benefit numeric(100,0) NOT NULL, + FOREIGN KEY (org_id) REFERENCES organisations(id) +); +CREATE INDEX organisation_payroll_idx_org_id ON organisation_payroll (org_id); +-- +-- Table: topics +-- +CREATE TABLE topics ( + id INTEGER PRIMARY KEY NOT NULL, + organisation_id integer, + name varchar(200) NOT NULL, + FOREIGN KEY (organisation_id) REFERENCES organisations(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX topics_idx_organisation_id ON topics (organisation_id); +-- +-- Table: organisations_external +-- +CREATE TABLE organisations_external ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + external_reference_id integer NOT NULL, + external_id varchar(255) NOT NULL, + FOREIGN KEY (external_reference_id) REFERENCES external_references(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (org_id) REFERENCES organisations(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX organisations_external_idx_external_reference_id ON organisations_external (external_reference_id); +CREATE INDEX organisations_external_idx_org_id ON organisations_external (org_id); +CREATE UNIQUE INDEX organisations_external_external_reference_id_external_id ON organisations_external (external_reference_id, external_id); +-- +-- Table: device_subscriptions +-- +CREATE TABLE device_subscriptions ( + id INTEGER PRIMARY KEY NOT NULL, + device_token_id integer NOT NULL, + topic_id integer NOT NULL, + FOREIGN KEY (device_token_id) REFERENCES device_tokens(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (topic_id) REFERENCES topics(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX device_subscriptions_idx_device_token_id ON device_subscriptions (device_token_id); +CREATE INDEX device_subscriptions_idx_topic_id ON device_subscriptions (topic_id); +COMMIT; diff --git a/share/ddl/SQLite/upgrade/33-34/001-auto.sql b/share/ddl/SQLite/upgrade/33-34/001-auto.sql new file mode 100644 index 0000000..11ff5df --- /dev/null +++ b/share/ddl/SQLite/upgrade/33-34/001-auto.sql @@ -0,0 +1,17 @@ +-- Convert schema 'share/ddl/_source/deploy/33/001-auto.yml' to 'share/ddl/_source/deploy/34/001-auto.yml':; + +; +BEGIN; + +; +ALTER TABLE topics ADD COLUMN organisation_id integer; + +; +CREATE INDEX topics_idx_organisation_id ON topics (organisation_id); + +; + +; + +COMMIT; + diff --git a/share/ddl/_source/deploy/34/001-auto-__VERSION.yml b/share/ddl/_source/deploy/34/001-auto-__VERSION.yml new file mode 100644 index 0000000..487f2d7 --- /dev/null +++ b/share/ddl/_source/deploy/34/001-auto-__VERSION.yml @@ -0,0 +1,91 @@ +--- +schema: + procedures: {} + tables: + dbix_class_deploymenthandler_versions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - version + match_type: '' + name: dbix_class_deploymenthandler_versions_version + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + ddl: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ddl + order: 3 + size: + - 0 + id: + data_type: int + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + upgrade_sql: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: upgrade_sql + order: 4 + size: + - 0 + version: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: version + order: 2 + size: + - 50 + indices: [] + name: dbix_class_deploymenthandler_versions + options: [] + order: 1 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - __VERSION + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 1.62 diff --git a/share/ddl/_source/deploy/34/001-auto.yml b/share/ddl/_source/deploy/34/001-auto.yml new file mode 100644 index 0000000..4231c7c --- /dev/null +++ b/share/ddl/_source/deploy/34/001-auto.yml @@ -0,0 +1,3785 @@ +--- +schema: + procedures: {} + tables: + account_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: account_tokens_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 0 + used: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: used + order: 3 + size: + - 0 + indices: [] + name: account_tokens + options: [] + order: 1 + category: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: category_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + line_icon: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: line_icon + order: 3 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 255 + indices: [] + name: category + options: [] + order: 2 + customers: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: customers_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + display_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: display_name + order: 3 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + full_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 4 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 7 + size: + - 5 + - 2 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 8 + size: + - 5 + - 2 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + year_of_birth: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: year_of_birth + order: 5 + size: + - 0 + indices: + - fields: + - entity_id + name: customers_idx_entity_id + options: [] + type: NORMAL + name: customers + options: [] + order: 12 + device_subscriptions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - device_token_id + match_type: '' + name: device_subscriptions_fk_device_token_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: device_tokens + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - topic_id + match_type: '' + name: device_subscriptions_fk_topic_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: topics + type: FOREIGN KEY + fields: + device_token_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: device_token_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + topic_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: topic_id + order: 3 + size: + - 0 + indices: + - fields: + - device_token_id + name: device_subscriptions_idx_device_token_id + options: [] + type: NORMAL + - fields: + - topic_id + name: device_subscriptions_idx_topic_id + options: [] + type: NORMAL + name: device_subscriptions + options: [] + order: 39 + device_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: device_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + register_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: register_date + order: 4 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: token + order: 3 + size: + - 200 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + indices: + - fields: + - user_id + name: device_tokens_idx_user_id + options: [] + type: NORMAL + name: device_tokens + options: [] + order: 20 + entities: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: type + order: 2 + size: + - 255 + indices: [] + name: entities + options: [] + order: 3 + entities_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + - entity_id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entities_postcodes_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: entities_postcodes_fk_outcode_incode + on_delete: '' + on_update: '' + options: [] + reference_fields: + - outcode + - incode + reference_table: gb_postcodes + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: entity_id + order: 3 + size: + - 0 + incode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + indices: + - fields: + - entity_id + name: entities_postcodes_idx_entity_id + options: [] + type: NORMAL + - fields: + - outcode + - incode + name: entities_postcodes_idx_outcode_incode + options: [] + type: NORMAL + name: entities_postcodes + options: [] + order: 30 + entity_association: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entity_association_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + esta: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: esta + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + lis: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: lis + order: 3 + size: + - 0 + indices: + - fields: + - entity_id + name: entity_association_idx_entity_id + options: [] + type: NORMAL + name: entity_association + options: [] + order: 13 + external_references: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: external_references_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 255 + indices: [] + name: external_references + options: [] + order: 4 + feedback: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: feedback_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + actioned: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: actioned + order: 9 + size: + - 0 + app_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: app_name + order: 5 + size: + - 255 + feedbacktext: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: feedbacktext + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + package_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: package_name + order: 6 + size: + - 255 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + version_code: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_code + order: 7 + size: + - 255 + version_number: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_number + order: 8 + size: + - 255 + indices: + - fields: + - user_id + name: feedback_idx_user_id + options: [] + type: NORMAL + name: feedback + options: [] + order: 21 + gb_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - ward_id + match_type: '' + name: gb_postcodes_fk_ward_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: gb_wards + type: FOREIGN KEY + fields: + incode: + data_type: char + default_value: '' + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 3 + size: + - 7 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 4 + size: + - 7 + - 5 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + ward_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ward_id + order: 5 + size: + - 0 + indices: + - fields: + - ward_id + name: gb_postcodes_idx_ward_id + options: [] + type: NORMAL + name: gb_postcodes + options: [] + order: 14 + gb_wards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ward: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ward + order: 2 + size: + - 100 + indices: [] + name: gb_wards + options: [] + order: 5 + global_medal_group: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - group_name + match_type: '' + name: global_medal_group_group_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + group_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: group_name + order: 2 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: global_medal_group + options: [] + order: 6 + global_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 3 + size: + - 0 + indices: + - fields: + - group_id + name: global_medals_idx_group_id + options: [] + type: NORMAL + name: global_medals + options: [] + order: 15 + global_user_medal_progress: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: global_user_medal_progress_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_user_medal_progress_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + total: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: total + order: 4 + size: + - 0 + indices: + - fields: + - entity_id + name: global_user_medal_progress_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: global_user_medal_progress_idx_group_id + options: [] + type: NORMAL + name: global_user_medal_progress + options: [] + order: 22 + global_user_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: global_user_medals_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_user_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + awarded_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: awarded_at + order: 5 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 6 + size: + - 0 + indices: + - fields: + - entity_id + name: global_user_medals_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: global_user_medals_idx_group_id + options: [] + type: NORMAL + name: global_user_medals + options: [] + order: 23 + import_lookups: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: import_lookups_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_lookups_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + indices: + - fields: + - entity_id + name: import_lookups_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: import_lookups_idx_set_id + options: [] + type: NORMAL + name: import_lookups + options: [] + order: 24 + import_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: import_sets + options: [] + order: 7 + import_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: import_values_fk_transaction_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ignore_value: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ignore_value + order: 8 + size: + - 0 + org_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_name + order: 6 + size: + - 255 + purchase_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_date + order: 4 + size: + - 0 + purchase_value: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_value + order: 5 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 7 + size: + - 0 + user_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_name + order: 3 + size: + - 255 + indices: + - fields: + - set_id + name: import_values_idx_set_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: import_values_idx_transaction_id + options: [] + type: NORMAL + name: import_values + options: [] + order: 31 + leaderboard_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - leaderboard_id + match_type: '' + name: leaderboard_sets_fk_leaderboard_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboards + type: FOREIGN KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + leaderboard_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: leaderboard_id + order: 2 + size: + - 0 + indices: + - fields: + - leaderboard_id + name: leaderboard_sets_idx_leaderboard_id + options: [] + type: NORMAL + name: leaderboard_sets + options: [] + order: 16 + leaderboard_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + - set_id + match_type: '' + name: leaderboard_values_entity_id_set_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - entity_id + match_type: '' + name: leaderboard_values_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: leaderboard_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboard_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + position: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: position + order: 4 + size: + - 0 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: set_id + order: 3 + size: + - 0 + trend: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: trend + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 5 + size: + - 100 + - 0 + indices: + - fields: + - entity_id + name: leaderboard_values_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: leaderboard_values_idx_set_id + options: [] + type: NORMAL + name: leaderboard_values + options: [] + order: 32 + leaderboards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - type + match_type: '' + name: leaderboards_type + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 255 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: type + order: 3 + size: + - 255 + indices: [] + name: leaderboards + options: [] + order: 8 + org_medal_group: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - group_name + match_type: '' + name: org_medal_group_group_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + group_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: group_name + order: 2 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: org_medal_group + options: [] + order: 9 + org_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 3 + size: + - 0 + indices: + - fields: + - group_id + name: org_medals_idx_group_id + options: [] + type: NORMAL + name: org_medals + options: [] + order: 17 + org_user_medal_progress: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: org_user_medal_progress_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_user_medal_progress_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + total: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: total + order: 4 + size: + - 0 + indices: + - fields: + - entity_id + name: org_user_medal_progress_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: org_user_medal_progress_idx_group_id + options: [] + type: NORMAL + name: org_user_medal_progress + options: [] + order: 25 + org_user_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: org_user_medals_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_user_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + awarded_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: awarded_at + order: 5 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 6 + size: + - 0 + indices: + - fields: + - entity_id + name: org_user_medals_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: org_user_medals_idx_group_id + options: [] + type: NORMAL + name: org_user_medals + options: [] + order: 26 + organisation_payroll: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisation_payroll_fk_org_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: employee_amount + order: 5 + size: + - 0 + entry_period: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entry_period + order: 4 + size: + - 0 + gross_payroll: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_payroll + order: 7 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_employee_amount + order: 6 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + payroll_employee_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employee_ni + order: 9 + size: + - 100 + - 0 + payroll_employer_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employer_ni + order: 10 + size: + - 100 + - 0 + payroll_income_tax: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_income_tax + order: 8 + size: + - 100 + - 0 + payroll_other_benefit: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_other_benefit + order: 12 + size: + - 100 + - 0 + payroll_total_pension: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_total_pension + order: 11 + size: + - 100 + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + indices: + - fields: + - org_id + name: organisation_payroll_idx_org_id + options: [] + type: NORMAL + name: organisation_payroll + options: [] + order: 36 + organisation_social_types: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - key + match_type: '' + name: organisation_social_types_key + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + key: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: key + order: 2 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + indices: [] + name: organisation_social_types + options: [] + order: 10 + organisation_types: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - key + match_type: '' + name: organisation_types_key + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + key: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: key + order: 2 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + indices: [] + name: organisation_types + options: [] + order: 11 + organisations: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: organisations_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - type_id + match_type: '' + name: organisations_fk_type_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisation_types + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - social_type_id + match_type: '' + name: organisations_fk_social_type_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisation_social_types + type: FOREIGN KEY + fields: + country: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: country + order: 7 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_anchor: + data_type: boolean + default_value: !!perl/ref + =: FALSE + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_anchor + order: 17 + size: + - 0 + is_fair: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_fair + order: 11 + size: + - 0 + is_local: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_local + order: 10 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 13 + size: + - 8 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 14 + size: + - 8 + - 5 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + pending: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: pending + order: 9 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + sector: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: sector + order: 8 + size: + - 1 + social_type_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: social_type_id + order: 16 + size: + - 0 + street_name: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: street_name + order: 4 + size: + - 0 + submitted_by_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: submitted_by_id + order: 12 + size: + - 0 + town: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: town + order: 5 + size: + - 255 + type_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: type_id + order: 15 + size: + - 0 + indices: + - fields: + - entity_id + name: organisations_idx_entity_id + options: [] + type: NORMAL + - fields: + - type_id + name: organisations_idx_type_id + options: [] + type: NORMAL + - fields: + - social_type_id + name: organisations_idx_social_type_id + options: [] + type: NORMAL + name: organisations + options: [] + order: 33 + organisations_external: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - external_reference_id + - external_id + match_type: '' + name: organisations_external_external_reference_id_external_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - external_reference_id + match_type: '' + name: organisations_external_fk_external_reference_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: external_references + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisations_external_fk_org_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + external_id: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_id + order: 4 + size: + - 255 + external_reference_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_reference_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + indices: + - fields: + - external_reference_id + name: organisations_external_idx_external_reference_id + options: [] + type: NORMAL + - fields: + - org_id + name: organisations_external_idx_org_id + options: [] + type: NORMAL + name: organisations_external + options: [] + order: 38 + session_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - token + match_type: '' + name: session_tokens_token + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: session_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: token + order: 2 + size: + - 255 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 3 + size: + - 0 + indices: + - fields: + - user_id + name: session_tokens_idx_user_id + options: [] + type: NORMAL + name: session_tokens + options: [] + order: 27 + topics: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - organisation_id + match_type: '' + name: topics_fk_organisation_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 200 + organisation_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: organisation_id + order: 2 + size: + - 0 + indices: + - fields: + - organisation_id + name: topics_idx_organisation_id + options: [] + type: NORMAL + name: topics + options: [] + order: 37 + transaction_category: + constraints: + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_transaction_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - category_id + match_type: '' + name: transaction_category_fk_category_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: category + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_fk_transaction_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + category_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: category_id + order: 1 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - category_id + name: transaction_category_idx_category_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: transaction_category_idx_transaction_id + options: [] + type: NORMAL + name: transaction_category + options: [] + order: 34 + transaction_recurring: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transaction_recurring_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - category_id + match_type: '' + name: transaction_recurring_fk_category_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: category + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transaction_recurring_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + category_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: category_id + order: 9 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 8 + size: + - 15 + essential: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: essential + order: 7 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + last_updated: + data_type: datetime + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: last_updated + order: 6 + size: + - 0 + recurring_period: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: recurring_period + order: 10 + size: + - 255 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + start_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: start_time + order: 5 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transaction_recurring_idx_buyer_id + options: [] + type: NORMAL + - fields: + - category_id + name: transaction_recurring_idx_category_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transaction_recurring_idx_seller_id + options: [] + type: NORMAL + name: transaction_recurring + options: [] + order: 28 + transactions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transactions_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transactions_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 9 + size: + - 15 + essential: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: essential + order: 8 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + proof_image: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: proof_image + order: 5 + size: + - 0 + purchase_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_time + order: 7 + size: + - 0 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transactions_idx_buyer_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transactions_idx_seller_id + options: [] + type: NORMAL + name: transactions + options: [] + order: 18 + transactions_external: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - external_reference_id + - external_id + match_type: '' + name: transactions_external_external_reference_id_external_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - external_reference_id + match_type: '' + name: transactions_external_fk_external_reference_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: external_references + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transactions_external_fk_transaction_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + external_id: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_id + order: 4 + size: + - 255 + external_reference_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_reference_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - external_reference_id + name: transactions_external_idx_external_reference_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: transactions_external_idx_transaction_id + options: [] + type: NORMAL + name: transactions_external + options: [] + order: 35 + transactions_meta: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transactions_meta_fk_transaction_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + business_tax_and_rebate: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: business_tax_and_rebate + order: 10 + size: + - 0 + central_loc_gov: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: central_loc_gov + order: 12 + size: + - 0 + gross_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_value + order: 5 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_service + order: 6 + size: + - 0 + national_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: national_service + order: 8 + size: + - 0 + net_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: net_value + order: 3 + size: + - 100 + - 0 + private_household_rebate: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: private_household_rebate + order: 9 + size: + - 0 + regional_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: regional_service + order: 7 + size: + - 0 + sales_tax_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: sales_tax_value + order: 4 + size: + - 100 + - 0 + stat_loc_gov: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: stat_loc_gov + order: 11 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - transaction_id + name: transactions_meta_idx_transaction_id + options: [] + type: NORMAL + name: transactions_meta + options: [] + order: 29 + users: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: users_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: users_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 3 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_admin: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_admin + order: 6 + size: + - 0 + join_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: join_date + order: 4 + size: + - 0 + password: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: password + order: 5 + size: + - 100 + indices: + - fields: + - entity_id + name: users_idx_entity_id + options: [] + type: NORMAL + name: users + options: [] + order: 19 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - AccountToken + - Category + - Customer + - DeviceSubscription + - DeviceToken + - Entity + - EntityAssociation + - EntityPostcode + - ExternalReference + - Feedback + - GbPostcode + - GbWard + - GlobalMedalGroup + - GlobalMedals + - GlobalUserMedalProgress + - GlobalUserMedals + - ImportLookup + - ImportSet + - ImportValue + - Leaderboard + - LeaderboardSet + - LeaderboardValue + - OrgMedalGroup + - OrgMedals + - OrgUserMedalProgress + - OrgUserMedals + - Organisation + - OrganisationExternal + - OrganisationPayroll + - OrganisationSocialType + - OrganisationType + - SessionToken + - Topic + - Transaction + - TransactionCategory + - TransactionExternal + - TransactionMeta + - TransactionRecurring + - User + - ViewQuantisedTransactionCategoryPg + - ViewQuantisedTransactionCategorySQLite + - ViewQuantisedTransactionPg + - ViewQuantisedTransactionSQLite + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 1.62 From c4bbc09b1f947decacd3226a26296d4f7e196d0e Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Sun, 21 Mar 2021 16:34:26 +0000 Subject: [PATCH 284/289] Correct command in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ffd1d4..a863685 100644 --- a/README.md +++ b/README.md @@ -138,8 +138,8 @@ Test files are found in the `t/` directory. Run `for f in ./lib/**/*.pm; do perltidy -b $f; done` to format all Perl files with [Perl-Tidy](https://metacpan.org/release/Perl-Tidy) (there is no built-in option to format files recursively). This will produce backup files with `.bak` -extensions, so run `rm -r *.bak` to clean up your local copy if you are happy -with the formatted files. +extensions, so run `find . -name '*.bak' -delete` to clean up your local copy +if you are happy with the formatted files. Run `perlcritic lib` to lint all Perl files with [Perl-Critic](https://metacpan.org/release/Perl-Critic). From 8fd5aff4d9aa56f68e16c4f1bc32127c341ded4b Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Thu, 25 Mar 2021 13:53:40 +0000 Subject: [PATCH 285/289] Update database --- .../deploy/35/001-auto-__VERSION.sql | 18 + share/ddl/PostgreSQL/deploy/35/001-auto.sql | 754 ++++ .../ddl/PostgreSQL/upgrade/34-35/001-auto.sql | 30 + .../SQLite/deploy/35/001-auto-__VERSION.sql | 18 + share/ddl/SQLite/deploy/35/001-auto.sql | 503 +++ share/ddl/SQLite/upgrade/34-35/001-auto.sql | 27 + .../_source/deploy/35/001-auto-__VERSION.yml | 91 + share/ddl/_source/deploy/35/001-auto.yml | 3785 +++++++++++++++++ 8 files changed, 5226 insertions(+) create mode 100644 share/ddl/PostgreSQL/deploy/35/001-auto-__VERSION.sql create mode 100644 share/ddl/PostgreSQL/deploy/35/001-auto.sql create mode 100644 share/ddl/PostgreSQL/upgrade/34-35/001-auto.sql create mode 100644 share/ddl/SQLite/deploy/35/001-auto-__VERSION.sql create mode 100644 share/ddl/SQLite/deploy/35/001-auto.sql create mode 100644 share/ddl/SQLite/upgrade/34-35/001-auto.sql create mode 100644 share/ddl/_source/deploy/35/001-auto-__VERSION.yml create mode 100644 share/ddl/_source/deploy/35/001-auto.yml diff --git a/share/ddl/PostgreSQL/deploy/35/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/35/001-auto-__VERSION.sql new file mode 100644 index 0000000..32b7266 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/35/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Thu Mar 25 12:58:12 2021 +-- +; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE "dbix_class_deploymenthandler_versions" ( + "id" serial NOT NULL, + "version" character varying(50) NOT NULL, + "ddl" text, + "upgrade_sql" text, + PRIMARY KEY ("id"), + CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version") +); + +; diff --git a/share/ddl/PostgreSQL/deploy/35/001-auto.sql b/share/ddl/PostgreSQL/deploy/35/001-auto.sql new file mode 100644 index 0000000..06cec30 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/35/001-auto.sql @@ -0,0 +1,754 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Thu Mar 25 12:58:11 2021 +-- +; +-- +-- Table: account_tokens +-- +CREATE TABLE "account_tokens" ( + "id" serial NOT NULL, + "name" text NOT NULL, + "used" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "account_tokens_name" UNIQUE ("name") +); + +; +-- +-- Table: category +-- +CREATE TABLE "category" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "line_icon" character varying(255), + PRIMARY KEY ("id"), + CONSTRAINT "category_name" UNIQUE ("name") +); + +; +-- +-- Table: entities +-- +CREATE TABLE "entities" ( + "id" serial NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: external_references +-- +CREATE TABLE "external_references" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "external_references_name" UNIQUE ("name") +); + +; +-- +-- Table: gb_wards +-- +CREATE TABLE "gb_wards" ( + "id" serial NOT NULL, + "ward" character varying(100) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: global_medal_group +-- +CREATE TABLE "global_medal_group" ( + "id" serial NOT NULL, + "group_name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "global_medal_group_group_name" UNIQUE ("group_name") +); + +; +-- +-- Table: import_sets +-- +CREATE TABLE "import_sets" ( + "id" serial NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: leaderboards +-- +CREATE TABLE "leaderboards" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboards_type" UNIQUE ("type") +); + +; +-- +-- Table: org_medal_group +-- +CREATE TABLE "org_medal_group" ( + "id" serial NOT NULL, + "group_name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "org_medal_group_group_name" UNIQUE ("group_name") +); + +; +-- +-- Table: organisation_social_types +-- +CREATE TABLE "organisation_social_types" ( + "id" serial NOT NULL, + "key" character varying(255) NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisation_social_types_key" UNIQUE ("key") +); + +; +-- +-- Table: organisation_types +-- +CREATE TABLE "organisation_types" ( + "id" serial NOT NULL, + "key" character varying(255) NOT NULL, + "name" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisation_types_key" UNIQUE ("key") +); + +; +-- +-- Table: customers +-- +CREATE TABLE "customers" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "display_name" character varying(255) NOT NULL, + "full_name" character varying(255) NOT NULL, + "year_of_birth" integer NOT NULL, + "postcode" character varying(16) NOT NULL, + "latitude" numeric(5,2), + "longitude" numeric(5,2), + PRIMARY KEY ("id") +); +CREATE INDEX "customers_idx_entity_id" on "customers" ("entity_id"); + +; +-- +-- Table: entity_association +-- +CREATE TABLE "entity_association" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "lis" boolean, + "esta" boolean, + PRIMARY KEY ("id") +); +CREATE INDEX "entity_association_idx_entity_id" on "entity_association" ("entity_id"); + +; +-- +-- Table: gb_postcodes +-- +CREATE TABLE "gb_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) DEFAULT '' NOT NULL, + "latitude" numeric(7,5), + "longitude" numeric(7,5), + "ward_id" integer, + PRIMARY KEY ("outcode", "incode") +); +CREATE INDEX "gb_postcodes_idx_ward_id" on "gb_postcodes" ("ward_id"); + +; +-- +-- Table: global_medals +-- +CREATE TABLE "global_medals" ( + "id" serial NOT NULL, + "group_id" integer NOT NULL, + "threshold" integer NOT NULL, + "points" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_medals_idx_group_id" on "global_medals" ("group_id"); + +; +-- +-- Table: leaderboard_sets +-- +CREATE TABLE "leaderboard_sets" ( + "id" serial NOT NULL, + "leaderboard_id" integer NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "leaderboard_sets_idx_leaderboard_id" on "leaderboard_sets" ("leaderboard_id"); + +; +-- +-- Table: org_medals +-- +CREATE TABLE "org_medals" ( + "id" serial NOT NULL, + "group_id" integer NOT NULL, + "threshold" integer NOT NULL, + "points" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_medals_idx_group_id" on "org_medals" ("group_id"); + +; +-- +-- Table: transactions +-- +CREATE TABLE "transactions" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "proof_image" text, + "submitted_at" timestamp NOT NULL, + "purchase_time" timestamp NOT NULL, + "essential" boolean DEFAULT false NOT NULL, + "distance" numeric(15), + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_idx_buyer_id" on "transactions" ("buyer_id"); +CREATE INDEX "transactions_idx_seller_id" on "transactions" ("seller_id"); + +; +-- +-- Table: users +-- +CREATE TABLE "users" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "email" text NOT NULL, + "join_date" timestamp NOT NULL, + "password" character varying(100) NOT NULL, + "is_admin" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "users_email" UNIQUE ("email") +); +CREATE INDEX "users_idx_entity_id" on "users" ("entity_id"); + +; +-- +-- Table: device_tokens +-- +CREATE TABLE "device_tokens" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "token" character varying(200) NOT NULL, + "register_date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "device_tokens_idx_user_id" on "device_tokens" ("user_id"); + +; +-- +-- Table: feedback +-- +CREATE TABLE "feedback" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "feedbacktext" text NOT NULL, + "app_name" character varying(255) NOT NULL, + "package_name" character varying(255) NOT NULL, + "version_code" character varying(255) NOT NULL, + "version_number" character varying(255) NOT NULL, + "actioned" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "feedback_idx_user_id" on "feedback" ("user_id"); + +; +-- +-- Table: global_user_medal_progress +-- +CREATE TABLE "global_user_medal_progress" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "total" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_user_medal_progress_idx_entity_id" on "global_user_medal_progress" ("entity_id"); +CREATE INDEX "global_user_medal_progress_idx_group_id" on "global_user_medal_progress" ("group_id"); + +; +-- +-- Table: global_user_medals +-- +CREATE TABLE "global_user_medals" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "points" integer NOT NULL, + "awarded_at" timestamp NOT NULL, + "threshold" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "global_user_medals_idx_entity_id" on "global_user_medals" ("entity_id"); +CREATE INDEX "global_user_medals_idx_group_id" on "global_user_medals" ("group_id"); + +; +-- +-- Table: import_lookups +-- +CREATE TABLE "import_lookups" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_lookups_idx_entity_id" on "import_lookups" ("entity_id"); +CREATE INDEX "import_lookups_idx_set_id" on "import_lookups" ("set_id"); + +; +-- +-- Table: org_user_medal_progress +-- +CREATE TABLE "org_user_medal_progress" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "total" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_user_medal_progress_idx_entity_id" on "org_user_medal_progress" ("entity_id"); +CREATE INDEX "org_user_medal_progress_idx_group_id" on "org_user_medal_progress" ("group_id"); + +; +-- +-- Table: org_user_medals +-- +CREATE TABLE "org_user_medals" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "group_id" integer NOT NULL, + "points" integer NOT NULL, + "awarded_at" timestamp NOT NULL, + "threshold" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "org_user_medals_idx_entity_id" on "org_user_medals" ("entity_id"); +CREATE INDEX "org_user_medals_idx_group_id" on "org_user_medals" ("group_id"); + +; +-- +-- Table: session_tokens +-- +CREATE TABLE "session_tokens" ( + "id" serial NOT NULL, + "token" character varying(255) NOT NULL, + "user_id" integer NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "session_tokens_token" UNIQUE ("token") +); +CREATE INDEX "session_tokens_idx_user_id" on "session_tokens" ("user_id"); + +; +-- +-- Table: transaction_recurring +-- +CREATE TABLE "transaction_recurring" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "start_time" timestamp NOT NULL, + "last_updated" timestamp, + "essential" boolean DEFAULT false NOT NULL, + "distance" numeric(15), + "category_id" integer, + "recurring_period" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transaction_recurring_idx_buyer_id" on "transaction_recurring" ("buyer_id"); +CREATE INDEX "transaction_recurring_idx_category_id" on "transaction_recurring" ("category_id"); +CREATE INDEX "transaction_recurring_idx_seller_id" on "transaction_recurring" ("seller_id"); + +; +-- +-- Table: transactions_meta +-- +CREATE TABLE "transactions_meta" ( + "id" serial NOT NULL, + "transaction_id" integer NOT NULL, + "net_value" numeric(100,0) NOT NULL, + "sales_tax_value" numeric(100,0) NOT NULL, + "gross_value" numeric(100,0) NOT NULL, + "local_service" boolean DEFAULT false NOT NULL, + "regional_service" boolean DEFAULT false NOT NULL, + "national_service" boolean DEFAULT false NOT NULL, + "private_household_rebate" boolean DEFAULT false NOT NULL, + "business_tax_and_rebate" boolean DEFAULT false NOT NULL, + "stat_loc_gov" boolean DEFAULT false NOT NULL, + "central_loc_gov" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_meta_idx_transaction_id" on "transactions_meta" ("transaction_id"); + +; +-- +-- Table: entities_postcodes +-- +CREATE TABLE "entities_postcodes" ( + "outcode" character(4) NOT NULL, + "incode" character(3) NOT NULL, + "entity_id" integer NOT NULL, + PRIMARY KEY ("outcode", "incode", "entity_id") +); +CREATE INDEX "entities_postcodes_idx_entity_id" on "entities_postcodes" ("entity_id"); +CREATE INDEX "entities_postcodes_idx_outcode_incode" on "entities_postcodes" ("outcode", "incode"); + +; +-- +-- Table: import_values +-- +CREATE TABLE "import_values" ( + "id" serial NOT NULL, + "set_id" integer NOT NULL, + "user_name" character varying(255) NOT NULL, + "purchase_date" timestamp NOT NULL, + "purchase_value" character varying(255) NOT NULL, + "org_name" character varying(255) NOT NULL, + "transaction_id" integer, + "ignore_value" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "import_values_idx_set_id" on "import_values" ("set_id"); +CREATE INDEX "import_values_idx_transaction_id" on "import_values" ("transaction_id"); + +; +-- +-- Table: leaderboard_values +-- +CREATE TABLE "leaderboard_values" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "set_id" integer NOT NULL, + "position" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "trend" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboard_values_entity_id_set_id" UNIQUE ("entity_id", "set_id") +); +CREATE INDEX "leaderboard_values_idx_entity_id" on "leaderboard_values" ("entity_id"); +CREATE INDEX "leaderboard_values_idx_set_id" on "leaderboard_values" ("set_id"); + +; +-- +-- Table: organisations +-- +CREATE TABLE "organisations" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "street_name" text, + "town" character varying(255) NOT NULL, + "postcode" character varying(16), + "country" character varying(255), + "sector" character varying(1), + "pending" boolean DEFAULT false NOT NULL, + "is_local" boolean, + "is_fair" boolean, + "submitted_by_id" integer, + "latitude" numeric(8,5), + "longitude" numeric(8,5), + "type_id" integer, + "social_type_id" integer, + "is_anchor" boolean DEFAULT FALSE NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisations_idx_entity_id" on "organisations" ("entity_id"); +CREATE INDEX "organisations_idx_type_id" on "organisations" ("type_id"); +CREATE INDEX "organisations_idx_social_type_id" on "organisations" ("social_type_id"); + +; +-- +-- Table: transaction_category +-- +CREATE TABLE "transaction_category" ( + "category_id" integer NOT NULL, + "transaction_id" integer NOT NULL, + CONSTRAINT "transaction_category_transaction_id" UNIQUE ("transaction_id") +); +CREATE INDEX "transaction_category_idx_category_id" on "transaction_category" ("category_id"); +CREATE INDEX "transaction_category_idx_transaction_id" on "transaction_category" ("transaction_id"); + +; +-- +-- Table: transactions_external +-- +CREATE TABLE "transactions_external" ( + "id" serial NOT NULL, + "transaction_id" integer NOT NULL, + "external_reference_id" integer NOT NULL, + "external_id" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "transactions_external_external_reference_id_external_id" UNIQUE ("external_reference_id", "external_id") +); +CREATE INDEX "transactions_external_idx_external_reference_id" on "transactions_external" ("external_reference_id"); +CREATE INDEX "transactions_external_idx_transaction_id" on "transactions_external" ("transaction_id"); + +; +-- +-- Table: organisation_payroll +-- +CREATE TABLE "organisation_payroll" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "entry_period" timestamp NOT NULL, + "employee_amount" integer NOT NULL, + "local_employee_amount" integer NOT NULL, + "gross_payroll" numeric(100,0) NOT NULL, + "payroll_income_tax" numeric(100,0) NOT NULL, + "payroll_employee_ni" numeric(100,0) NOT NULL, + "payroll_employer_ni" numeric(100,0) NOT NULL, + "payroll_total_pension" numeric(100,0) NOT NULL, + "payroll_other_benefit" numeric(100,0) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisation_payroll_idx_org_id" on "organisation_payroll" ("org_id"); + +; +-- +-- Table: topics +-- +CREATE TABLE "topics" ( + "id" serial NOT NULL, + "organisation_id" integer, + "name" character varying(200) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "topics_idx_organisation_id" on "topics" ("organisation_id"); + +; +-- +-- Table: organisations_external +-- +CREATE TABLE "organisations_external" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "external_reference_id" integer NOT NULL, + "external_id" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "organisations_external_external_reference_id_external_id" UNIQUE ("external_reference_id", "external_id") +); +CREATE INDEX "organisations_external_idx_external_reference_id" on "organisations_external" ("external_reference_id"); +CREATE INDEX "organisations_external_idx_org_id" on "organisations_external" ("org_id"); + +; +-- +-- Table: user_topic_subscriptions +-- +CREATE TABLE "user_topic_subscriptions" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "topic_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "user_topic_subscriptions_idx_topic_id" on "user_topic_subscriptions" ("topic_id"); +CREATE INDEX "user_topic_subscriptions_idx_user_id" on "user_topic_subscriptions" ("user_id"); + +; +-- +-- Foreign Key Definitions +-- + +; +ALTER TABLE "customers" ADD CONSTRAINT "customers_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entity_association" ADD CONSTRAINT "entity_association_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "gb_postcodes" ADD CONSTRAINT "gb_postcodes_fk_ward_id" FOREIGN KEY ("ward_id") + REFERENCES "gb_wards" ("id") DEFERRABLE; + +; +ALTER TABLE "global_medals" ADD CONSTRAINT "global_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_sets" ADD CONSTRAINT "leaderboard_sets_fk_leaderboard_id" FOREIGN KEY ("leaderboard_id") + REFERENCES "leaderboards" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_medals" ADD CONSTRAINT "org_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "users" ADD CONSTRAINT "users_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "device_tokens" ADD CONSTRAINT "device_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "feedback" ADD CONSTRAINT "feedback_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "global_user_medal_progress" ADD CONSTRAINT "global_user_medal_progress_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "global_user_medal_progress" ADD CONSTRAINT "global_user_medal_progress_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "global_user_medals" ADD CONSTRAINT "global_user_medals_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "global_user_medals" ADD CONSTRAINT "global_user_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "global_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "import_lookups" ADD CONSTRAINT "import_lookups_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_user_medal_progress" ADD CONSTRAINT "org_user_medal_progress_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "org_user_medal_progress" ADD CONSTRAINT "org_user_medal_progress_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "org_user_medals" ADD CONSTRAINT "org_user_medals_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") DEFERRABLE; + +; +ALTER TABLE "org_user_medals" ADD CONSTRAINT "org_user_medals_fk_group_id" FOREIGN KEY ("group_id") + REFERENCES "org_medal_group" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "session_tokens" ADD CONSTRAINT "session_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") DEFERRABLE; + +; +ALTER TABLE "transaction_recurring" ADD CONSTRAINT "transaction_recurring_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions_meta" ADD CONSTRAINT "transactions_meta_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entities_postcodes" ADD CONSTRAINT "entities_postcodes_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "entities_postcodes" ADD CONSTRAINT "entities_postcodes_fk_outcode_incode" FOREIGN KEY ("outcode", "incode") + REFERENCES "gb_postcodes" ("outcode", "incode") DEFERRABLE; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "import_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "import_values" ADD CONSTRAINT "import_values_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "leaderboard_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_type_id" FOREIGN KEY ("type_id") + REFERENCES "organisation_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_social_type_id" FOREIGN KEY ("social_type_id") + REFERENCES "organisation_social_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_category_id" FOREIGN KEY ("category_id") + REFERENCES "category" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transaction_category" ADD CONSTRAINT "transaction_category_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions_external" ADD CONSTRAINT "transactions_external_fk_external_reference_id" FOREIGN KEY ("external_reference_id") + REFERENCES "external_references" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions_external" ADD CONSTRAINT "transactions_external_fk_transaction_id" FOREIGN KEY ("transaction_id") + REFERENCES "transactions" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisation_payroll" ADD CONSTRAINT "organisation_payroll_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") DEFERRABLE; + +; +ALTER TABLE "topics" ADD CONSTRAINT "topics_fk_organisation_id" FOREIGN KEY ("organisation_id") + REFERENCES "organisations" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations_external" ADD CONSTRAINT "organisations_external_fk_external_reference_id" FOREIGN KEY ("external_reference_id") + REFERENCES "external_references" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "organisations_external" ADD CONSTRAINT "organisations_external_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +; +ALTER TABLE "user_topic_subscriptions" ADD CONSTRAINT "user_topic_subscriptions_fk_topic_id" FOREIGN KEY ("topic_id") + REFERENCES "topics" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "user_topic_subscriptions" ADD CONSTRAINT "user_topic_subscriptions_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; diff --git a/share/ddl/PostgreSQL/upgrade/34-35/001-auto.sql b/share/ddl/PostgreSQL/upgrade/34-35/001-auto.sql new file mode 100644 index 0000000..1be55c2 --- /dev/null +++ b/share/ddl/PostgreSQL/upgrade/34-35/001-auto.sql @@ -0,0 +1,30 @@ +-- Convert schema 'share/ddl/_source/deploy/34/001-auto.yml' to 'share/ddl/_source/deploy/35/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE "user_topic_subscriptions" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "topic_id" integer NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "user_topic_subscriptions_idx_topic_id" on "user_topic_subscriptions" ("topic_id"); +CREATE INDEX "user_topic_subscriptions_idx_user_id" on "user_topic_subscriptions" ("user_id"); + +; +ALTER TABLE "user_topic_subscriptions" ADD CONSTRAINT "user_topic_subscriptions_fk_topic_id" FOREIGN KEY ("topic_id") + REFERENCES "topics" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "user_topic_subscriptions" ADD CONSTRAINT "user_topic_subscriptions_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +DROP TABLE device_subscriptions CASCADE; + +; + +COMMIT; + diff --git a/share/ddl/SQLite/deploy/35/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/35/001-auto-__VERSION.sql new file mode 100644 index 0000000..eddbed9 --- /dev/null +++ b/share/ddl/SQLite/deploy/35/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Thu Mar 25 12:58:12 2021 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE dbix_class_deploymenthandler_versions ( + id INTEGER PRIMARY KEY NOT NULL, + version varchar(50) NOT NULL, + ddl text, + upgrade_sql text +); +CREATE UNIQUE INDEX dbix_class_deploymenthandler_versions_version ON dbix_class_deploymenthandler_versions (version); +COMMIT; diff --git a/share/ddl/SQLite/deploy/35/001-auto.sql b/share/ddl/SQLite/deploy/35/001-auto.sql new file mode 100644 index 0000000..70c28c7 --- /dev/null +++ b/share/ddl/SQLite/deploy/35/001-auto.sql @@ -0,0 +1,503 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Thu Mar 25 12:58:11 2021 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: account_tokens +-- +CREATE TABLE account_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + name text NOT NULL, + used integer NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX account_tokens_name ON account_tokens (name); +-- +-- Table: category +-- +CREATE TABLE category ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + line_icon varchar(255) +); +CREATE UNIQUE INDEX category_name ON category (name); +-- +-- Table: entities +-- +CREATE TABLE entities ( + id INTEGER PRIMARY KEY NOT NULL, + type varchar(255) NOT NULL +); +-- +-- Table: external_references +-- +CREATE TABLE external_references ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX external_references_name ON external_references (name); +-- +-- Table: gb_wards +-- +CREATE TABLE gb_wards ( + id INTEGER PRIMARY KEY NOT NULL, + ward varchar(100) NOT NULL +); +-- +-- Table: global_medal_group +-- +CREATE TABLE global_medal_group ( + id INTEGER PRIMARY KEY NOT NULL, + group_name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX global_medal_group_group_name ON global_medal_group (group_name); +-- +-- Table: import_sets +-- +CREATE TABLE import_sets ( + id INTEGER PRIMARY KEY NOT NULL, + date datetime NOT NULL +); +-- +-- Table: leaderboards +-- +CREATE TABLE leaderboards ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + type varchar(255) NOT NULL +); +CREATE UNIQUE INDEX leaderboards_type ON leaderboards (type); +-- +-- Table: org_medal_group +-- +CREATE TABLE org_medal_group ( + id INTEGER PRIMARY KEY NOT NULL, + group_name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX org_medal_group_group_name ON org_medal_group (group_name); +-- +-- Table: organisation_social_types +-- +CREATE TABLE organisation_social_types ( + id INTEGER PRIMARY KEY NOT NULL, + key varchar(255) NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX organisation_social_types_key ON organisation_social_types (key); +-- +-- Table: organisation_types +-- +CREATE TABLE organisation_types ( + id INTEGER PRIMARY KEY NOT NULL, + key varchar(255) NOT NULL, + name varchar(255) NOT NULL +); +CREATE UNIQUE INDEX organisation_types_key ON organisation_types (key); +-- +-- Table: customers +-- +CREATE TABLE customers ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + display_name varchar(255) NOT NULL, + full_name varchar(255) NOT NULL, + year_of_birth integer NOT NULL, + postcode varchar(16) NOT NULL, + latitude decimal(5,2), + longitude decimal(5,2), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX customers_idx_entity_id ON customers (entity_id); +-- +-- Table: entity_association +-- +CREATE TABLE entity_association ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + lis boolean, + esta boolean, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX entity_association_idx_entity_id ON entity_association (entity_id); +-- +-- Table: gb_postcodes +-- +CREATE TABLE gb_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL DEFAULT '', + latitude decimal(7,5), + longitude decimal(7,5), + ward_id integer, + PRIMARY KEY (outcode, incode), + FOREIGN KEY (ward_id) REFERENCES gb_wards(id) +); +CREATE INDEX gb_postcodes_idx_ward_id ON gb_postcodes (ward_id); +-- +-- Table: global_medals +-- +CREATE TABLE global_medals ( + id INTEGER PRIMARY KEY NOT NULL, + group_id integer NOT NULL, + threshold integer NOT NULL, + points integer NOT NULL, + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_medals_idx_group_id ON global_medals (group_id); +-- +-- Table: leaderboard_sets +-- +CREATE TABLE leaderboard_sets ( + id INTEGER PRIMARY KEY NOT NULL, + leaderboard_id integer NOT NULL, + date datetime NOT NULL, + FOREIGN KEY (leaderboard_id) REFERENCES leaderboards(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_sets_idx_leaderboard_id ON leaderboard_sets (leaderboard_id); +-- +-- Table: org_medals +-- +CREATE TABLE org_medals ( + id INTEGER PRIMARY KEY NOT NULL, + group_id integer NOT NULL, + threshold integer NOT NULL, + points integer NOT NULL, + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_medals_idx_group_id ON org_medals (group_id); +-- +-- Table: transactions +-- +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + essential boolean NOT NULL DEFAULT false, + distance numeric(15), + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transactions_idx_buyer_id ON transactions (buyer_id); +CREATE INDEX transactions_idx_seller_id ON transactions (seller_id); +-- +-- Table: users +-- +CREATE TABLE users ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + email text NOT NULL, + join_date datetime NOT NULL, + password varchar(100) NOT NULL, + is_admin boolean NOT NULL DEFAULT false, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX users_idx_entity_id ON users (entity_id); +CREATE UNIQUE INDEX users_email ON users (email); +-- +-- Table: device_tokens +-- +CREATE TABLE device_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + token varchar(200) NOT NULL, + register_date datetime NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX device_tokens_idx_user_id ON device_tokens (user_id); +-- +-- Table: feedback +-- +CREATE TABLE feedback ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + submitted_at datetime NOT NULL, + feedbacktext text NOT NULL, + app_name varchar(255) NOT NULL, + package_name varchar(255) NOT NULL, + version_code varchar(255) NOT NULL, + version_number varchar(255) NOT NULL, + actioned boolean NOT NULL DEFAULT false, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX feedback_idx_user_id ON feedback (user_id); +-- +-- Table: global_user_medal_progress +-- +CREATE TABLE global_user_medal_progress ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + total integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_user_medal_progress_idx_entity_id ON global_user_medal_progress (entity_id); +CREATE INDEX global_user_medal_progress_idx_group_id ON global_user_medal_progress (group_id); +-- +-- Table: global_user_medals +-- +CREATE TABLE global_user_medals ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + points integer NOT NULL, + awarded_at datetime NOT NULL, + threshold integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES global_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX global_user_medals_idx_entity_id ON global_user_medals (entity_id); +CREATE INDEX global_user_medals_idx_group_id ON global_user_medals (group_id); +-- +-- Table: import_lookups +-- +CREATE TABLE import_lookups ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + name varchar(255) NOT NULL, + entity_id integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_lookups_idx_entity_id ON import_lookups (entity_id); +CREATE INDEX import_lookups_idx_set_id ON import_lookups (set_id); +-- +-- Table: org_user_medal_progress +-- +CREATE TABLE org_user_medal_progress ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + total integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_user_medal_progress_idx_entity_id ON org_user_medal_progress (entity_id); +CREATE INDEX org_user_medal_progress_idx_group_id ON org_user_medal_progress (group_id); +-- +-- Table: org_user_medals +-- +CREATE TABLE org_user_medals ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + group_id integer NOT NULL, + points integer NOT NULL, + awarded_at datetime NOT NULL, + threshold integer NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id), + FOREIGN KEY (group_id) REFERENCES org_medal_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX org_user_medals_idx_entity_id ON org_user_medals (entity_id); +CREATE INDEX org_user_medals_idx_group_id ON org_user_medals (group_id); +-- +-- Table: session_tokens +-- +CREATE TABLE session_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + token varchar(255) NOT NULL, + user_id integer NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX session_tokens_idx_user_id ON session_tokens (user_id); +CREATE UNIQUE INDEX session_tokens_token ON session_tokens (token); +-- +-- Table: transaction_recurring +-- +CREATE TABLE transaction_recurring ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + start_time datetime NOT NULL, + last_updated datetime, + essential boolean NOT NULL DEFAULT false, + distance numeric(15), + category_id integer, + recurring_period varchar(255) NOT NULL, + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (category_id) REFERENCES category(id), + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transaction_recurring_idx_buyer_id ON transaction_recurring (buyer_id); +CREATE INDEX transaction_recurring_idx_category_id ON transaction_recurring (category_id); +CREATE INDEX transaction_recurring_idx_seller_id ON transaction_recurring (seller_id); +-- +-- Table: transactions_meta +-- +CREATE TABLE transactions_meta ( + id INTEGER PRIMARY KEY NOT NULL, + transaction_id integer NOT NULL, + net_value numeric(100,0) NOT NULL, + sales_tax_value numeric(100,0) NOT NULL, + gross_value numeric(100,0) NOT NULL, + local_service boolean NOT NULL DEFAULT false, + regional_service boolean NOT NULL DEFAULT false, + national_service boolean NOT NULL DEFAULT false, + private_household_rebate boolean NOT NULL DEFAULT false, + business_tax_and_rebate boolean NOT NULL DEFAULT false, + stat_loc_gov boolean NOT NULL DEFAULT false, + central_loc_gov boolean NOT NULL DEFAULT false, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); +CREATE INDEX transactions_meta_idx_transaction_id ON transactions_meta (transaction_id); +-- +-- Table: entities_postcodes +-- +CREATE TABLE entities_postcodes ( + outcode char(4) NOT NULL, + incode char(3) NOT NULL, + entity_id integer NOT NULL, + PRIMARY KEY (outcode, incode, entity_id), + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE, + FOREIGN KEY (outcode, incode) REFERENCES gb_postcodes(outcode, incode) +); +CREATE INDEX entities_postcodes_idx_entity_id ON entities_postcodes (entity_id); +CREATE INDEX entities_postcodes_idx_outcode_incode ON entities_postcodes (outcode, incode); +-- +-- Table: import_values +-- +CREATE TABLE import_values ( + id INTEGER PRIMARY KEY NOT NULL, + set_id integer NOT NULL, + user_name varchar(255) NOT NULL, + purchase_date datetime NOT NULL, + purchase_value varchar(255) NOT NULL, + org_name varchar(255) NOT NULL, + transaction_id integer, + ignore_value boolean NOT NULL DEFAULT false, + FOREIGN KEY (set_id) REFERENCES import_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX import_values_idx_set_id ON import_values (set_id); +CREATE INDEX import_values_idx_transaction_id ON import_values (transaction_id); +-- +-- Table: leaderboard_values +-- +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_values_idx_entity_id ON leaderboard_values (entity_id); +CREATE INDEX leaderboard_values_idx_set_id ON leaderboard_values (set_id); +CREATE UNIQUE INDEX leaderboard_values_entity_id_set_id ON leaderboard_values (entity_id, set_id); +-- +-- Table: organisations +-- +CREATE TABLE organisations ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + name varchar(255) NOT NULL, + street_name text, + town varchar(255) NOT NULL, + postcode varchar(16), + country varchar(255), + sector varchar(1), + pending boolean NOT NULL DEFAULT false, + is_local boolean, + is_fair boolean, + submitted_by_id integer, + latitude decimal(8,5), + longitude decimal(8,5), + type_id integer, + social_type_id integer, + is_anchor boolean NOT NULL DEFAULT FALSE, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE, + FOREIGN KEY (type_id) REFERENCES organisation_types(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (social_type_id) REFERENCES organisation_social_types(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX organisations_idx_entity_id ON organisations (entity_id); +CREATE INDEX organisations_idx_type_id ON organisations (type_id); +CREATE INDEX organisations_idx_social_type_id ON organisations (social_type_id); +-- +-- Table: transaction_category +-- +CREATE TABLE transaction_category ( + category_id integer NOT NULL, + transaction_id integer NOT NULL, + FOREIGN KEY (category_id) REFERENCES category(id) ON DELETE CASCADE, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE +); +CREATE INDEX transaction_category_idx_category_id ON transaction_category (category_id); +CREATE INDEX transaction_category_idx_transaction_id ON transaction_category (transaction_id); +CREATE UNIQUE INDEX transaction_category_transaction_id ON transaction_category (transaction_id); +-- +-- Table: transactions_external +-- +CREATE TABLE transactions_external ( + id INTEGER PRIMARY KEY NOT NULL, + transaction_id integer NOT NULL, + external_reference_id integer NOT NULL, + external_id varchar(255) NOT NULL, + FOREIGN KEY (external_reference_id) REFERENCES external_references(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX transactions_external_idx_external_reference_id ON transactions_external (external_reference_id); +CREATE INDEX transactions_external_idx_transaction_id ON transactions_external (transaction_id); +CREATE UNIQUE INDEX transactions_external_external_reference_id_external_id ON transactions_external (external_reference_id, external_id); +-- +-- Table: organisation_payroll +-- +CREATE TABLE organisation_payroll ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + submitted_at datetime NOT NULL, + entry_period datetime NOT NULL, + employee_amount integer NOT NULL, + local_employee_amount integer NOT NULL, + gross_payroll numeric(100,0) NOT NULL, + payroll_income_tax numeric(100,0) NOT NULL, + payroll_employee_ni numeric(100,0) NOT NULL, + payroll_employer_ni numeric(100,0) NOT NULL, + payroll_total_pension numeric(100,0) NOT NULL, + payroll_other_benefit numeric(100,0) NOT NULL, + FOREIGN KEY (org_id) REFERENCES organisations(id) +); +CREATE INDEX organisation_payroll_idx_org_id ON organisation_payroll (org_id); +-- +-- Table: topics +-- +CREATE TABLE topics ( + id INTEGER PRIMARY KEY NOT NULL, + organisation_id integer, + name varchar(200) NOT NULL, + FOREIGN KEY (organisation_id) REFERENCES organisations(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX topics_idx_organisation_id ON topics (organisation_id); +-- +-- Table: organisations_external +-- +CREATE TABLE organisations_external ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + external_reference_id integer NOT NULL, + external_id varchar(255) NOT NULL, + FOREIGN KEY (external_reference_id) REFERENCES external_references(id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (org_id) REFERENCES organisations(id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX organisations_external_idx_external_reference_id ON organisations_external (external_reference_id); +CREATE INDEX organisations_external_idx_org_id ON organisations_external (org_id); +CREATE UNIQUE INDEX organisations_external_external_reference_id_external_id ON organisations_external (external_reference_id, external_id); +-- +-- Table: user_topic_subscriptions +-- +CREATE TABLE user_topic_subscriptions ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + topic_id integer NOT NULL, + FOREIGN KEY (topic_id) REFERENCES topics(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX user_topic_subscriptions_idx_topic_id ON user_topic_subscriptions (topic_id); +CREATE INDEX user_topic_subscriptions_idx_user_id ON user_topic_subscriptions (user_id); +COMMIT; diff --git a/share/ddl/SQLite/upgrade/34-35/001-auto.sql b/share/ddl/SQLite/upgrade/34-35/001-auto.sql new file mode 100644 index 0000000..4f5e254 --- /dev/null +++ b/share/ddl/SQLite/upgrade/34-35/001-auto.sql @@ -0,0 +1,27 @@ +-- Convert schema 'share/ddl/_source/deploy/34/001-auto.yml' to 'share/ddl/_source/deploy/35/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE user_topic_subscriptions ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + topic_id integer NOT NULL, + FOREIGN KEY (topic_id) REFERENCES topics(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); + +; +CREATE INDEX user_topic_subscriptions_idx_topic_id ON user_topic_subscriptions (topic_id); + +; +CREATE INDEX user_topic_subscriptions_idx_user_id ON user_topic_subscriptions (user_id); + +; +DROP TABLE device_subscriptions; + +; + +COMMIT; + diff --git a/share/ddl/_source/deploy/35/001-auto-__VERSION.yml b/share/ddl/_source/deploy/35/001-auto-__VERSION.yml new file mode 100644 index 0000000..487f2d7 --- /dev/null +++ b/share/ddl/_source/deploy/35/001-auto-__VERSION.yml @@ -0,0 +1,91 @@ +--- +schema: + procedures: {} + tables: + dbix_class_deploymenthandler_versions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - version + match_type: '' + name: dbix_class_deploymenthandler_versions_version + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + ddl: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ddl + order: 3 + size: + - 0 + id: + data_type: int + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + upgrade_sql: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: upgrade_sql + order: 4 + size: + - 0 + version: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: version + order: 2 + size: + - 50 + indices: [] + name: dbix_class_deploymenthandler_versions + options: [] + order: 1 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - __VERSION + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 1.62 diff --git a/share/ddl/_source/deploy/35/001-auto.yml b/share/ddl/_source/deploy/35/001-auto.yml new file mode 100644 index 0000000..2fadcc0 --- /dev/null +++ b/share/ddl/_source/deploy/35/001-auto.yml @@ -0,0 +1,3785 @@ +--- +schema: + procedures: {} + tables: + account_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: account_tokens_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 0 + used: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: used + order: 3 + size: + - 0 + indices: [] + name: account_tokens + options: [] + order: 1 + category: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: category_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + line_icon: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: line_icon + order: 3 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 255 + indices: [] + name: category + options: [] + order: 2 + customers: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: customers_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + display_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: display_name + order: 3 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + full_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 4 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 7 + size: + - 5 + - 2 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 8 + size: + - 5 + - 2 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + year_of_birth: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: year_of_birth + order: 5 + size: + - 0 + indices: + - fields: + - entity_id + name: customers_idx_entity_id + options: [] + type: NORMAL + name: customers + options: [] + order: 12 + device_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: device_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + register_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: register_date + order: 4 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: token + order: 3 + size: + - 200 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + indices: + - fields: + - user_id + name: device_tokens_idx_user_id + options: [] + type: NORMAL + name: device_tokens + options: [] + order: 20 + entities: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: type + order: 2 + size: + - 255 + indices: [] + name: entities + options: [] + order: 3 + entities_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + - entity_id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entities_postcodes_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: entities_postcodes_fk_outcode_incode + on_delete: '' + on_update: '' + options: [] + reference_fields: + - outcode + - incode + reference_table: gb_postcodes + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: entity_id + order: 3 + size: + - 0 + incode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + indices: + - fields: + - entity_id + name: entities_postcodes_idx_entity_id + options: [] + type: NORMAL + - fields: + - outcode + - incode + name: entities_postcodes_idx_outcode_incode + options: [] + type: NORMAL + name: entities_postcodes + options: [] + order: 30 + entity_association: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: entity_association_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + esta: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: esta + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + lis: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: lis + order: 3 + size: + - 0 + indices: + - fields: + - entity_id + name: entity_association_idx_entity_id + options: [] + type: NORMAL + name: entity_association + options: [] + order: 13 + external_references: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: external_references_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 255 + indices: [] + name: external_references + options: [] + order: 4 + feedback: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: feedback_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + actioned: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: actioned + order: 9 + size: + - 0 + app_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: app_name + order: 5 + size: + - 255 + feedbacktext: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: feedbacktext + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + package_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: package_name + order: 6 + size: + - 255 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + version_code: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_code + order: 7 + size: + - 255 + version_number: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_number + order: 8 + size: + - 255 + indices: + - fields: + - user_id + name: feedback_idx_user_id + options: [] + type: NORMAL + name: feedback + options: [] + order: 21 + gb_postcodes: + constraints: + - deferrable: 1 + expression: '' + fields: + - outcode + - incode + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - ward_id + match_type: '' + name: gb_postcodes_fk_ward_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: gb_wards + type: FOREIGN KEY + fields: + incode: + data_type: char + default_value: '' + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: incode + order: 2 + size: + - 3 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 3 + size: + - 7 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 4 + size: + - 7 + - 5 + outcode: + data_type: char + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: outcode + order: 1 + size: + - 4 + ward_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ward_id + order: 5 + size: + - 0 + indices: + - fields: + - ward_id + name: gb_postcodes_idx_ward_id + options: [] + type: NORMAL + name: gb_postcodes + options: [] + order: 14 + gb_wards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ward: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ward + order: 2 + size: + - 100 + indices: [] + name: gb_wards + options: [] + order: 5 + global_medal_group: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - group_name + match_type: '' + name: global_medal_group_group_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + group_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: group_name + order: 2 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: global_medal_group + options: [] + order: 6 + global_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 3 + size: + - 0 + indices: + - fields: + - group_id + name: global_medals_idx_group_id + options: [] + type: NORMAL + name: global_medals + options: [] + order: 15 + global_user_medal_progress: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: global_user_medal_progress_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_user_medal_progress_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + total: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: total + order: 4 + size: + - 0 + indices: + - fields: + - entity_id + name: global_user_medal_progress_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: global_user_medal_progress_idx_group_id + options: [] + type: NORMAL + name: global_user_medal_progress + options: [] + order: 22 + global_user_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: global_user_medals_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: global_user_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: global_medal_group + type: FOREIGN KEY + fields: + awarded_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: awarded_at + order: 5 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 6 + size: + - 0 + indices: + - fields: + - entity_id + name: global_user_medals_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: global_user_medals_idx_group_id + options: [] + type: NORMAL + name: global_user_medals + options: [] + order: 23 + import_lookups: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: import_lookups_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_lookups_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + indices: + - fields: + - entity_id + name: import_lookups_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: import_lookups_idx_set_id + options: [] + type: NORMAL + name: import_lookups + options: [] + order: 24 + import_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: import_sets + options: [] + order: 7 + import_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: import_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: import_sets + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: import_values_fk_transaction_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + ignore_value: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: ignore_value + order: 8 + size: + - 0 + org_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_name + order: 6 + size: + - 255 + purchase_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_date + order: 4 + size: + - 0 + purchase_value: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_value + order: 5 + size: + - 255 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: set_id + order: 2 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 7 + size: + - 0 + user_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_name + order: 3 + size: + - 255 + indices: + - fields: + - set_id + name: import_values_idx_set_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: import_values_idx_transaction_id + options: [] + type: NORMAL + name: import_values + options: [] + order: 31 + leaderboard_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - leaderboard_id + match_type: '' + name: leaderboard_sets_fk_leaderboard_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboards + type: FOREIGN KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + leaderboard_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: leaderboard_id + order: 2 + size: + - 0 + indices: + - fields: + - leaderboard_id + name: leaderboard_sets_idx_leaderboard_id + options: [] + type: NORMAL + name: leaderboard_sets + options: [] + order: 16 + leaderboard_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + - set_id + match_type: '' + name: leaderboard_values_entity_id_set_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - entity_id + match_type: '' + name: leaderboard_values_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: leaderboard_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboard_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + position: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: position + order: 4 + size: + - 0 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: set_id + order: 3 + size: + - 0 + trend: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: trend + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 5 + size: + - 100 + - 0 + indices: + - fields: + - entity_id + name: leaderboard_values_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: leaderboard_values_idx_set_id + options: [] + type: NORMAL + name: leaderboard_values + options: [] + order: 32 + leaderboards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - type + match_type: '' + name: leaderboards_type + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 255 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: type + order: 3 + size: + - 255 + indices: [] + name: leaderboards + options: [] + order: 8 + org_medal_group: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - group_name + match_type: '' + name: org_medal_group_group_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + group_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: group_name + order: 2 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + indices: [] + name: org_medal_group + options: [] + order: 9 + org_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 3 + size: + - 0 + indices: + - fields: + - group_id + name: org_medals_idx_group_id + options: [] + type: NORMAL + name: org_medals + options: [] + order: 17 + org_user_medal_progress: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: org_user_medal_progress_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_user_medal_progress_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + total: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: total + order: 4 + size: + - 0 + indices: + - fields: + - entity_id + name: org_user_medal_progress_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: org_user_medal_progress_idx_group_id + options: [] + type: NORMAL + name: org_user_medal_progress + options: [] + order: 25 + org_user_medals: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: org_user_medals_fk_entity_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - group_id + match_type: '' + name: org_user_medals_fk_group_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: org_medal_group + type: FOREIGN KEY + fields: + awarded_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: awarded_at + order: 5 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + group_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: group_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + points: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: points + order: 4 + size: + - 0 + threshold: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: threshold + order: 6 + size: + - 0 + indices: + - fields: + - entity_id + name: org_user_medals_idx_entity_id + options: [] + type: NORMAL + - fields: + - group_id + name: org_user_medals_idx_group_id + options: [] + type: NORMAL + name: org_user_medals + options: [] + order: 26 + organisation_payroll: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisation_payroll_fk_org_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: employee_amount + order: 5 + size: + - 0 + entry_period: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entry_period + order: 4 + size: + - 0 + gross_payroll: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_payroll + order: 7 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_employee_amount + order: 6 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + payroll_employee_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employee_ni + order: 9 + size: + - 100 + - 0 + payroll_employer_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employer_ni + order: 10 + size: + - 100 + - 0 + payroll_income_tax: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_income_tax + order: 8 + size: + - 100 + - 0 + payroll_other_benefit: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_other_benefit + order: 12 + size: + - 100 + - 0 + payroll_total_pension: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_total_pension + order: 11 + size: + - 100 + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + indices: + - fields: + - org_id + name: organisation_payroll_idx_org_id + options: [] + type: NORMAL + name: organisation_payroll + options: [] + order: 36 + organisation_social_types: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - key + match_type: '' + name: organisation_social_types_key + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + key: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: key + order: 2 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + indices: [] + name: organisation_social_types + options: [] + order: 10 + organisation_types: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - key + match_type: '' + name: organisation_types_key + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + key: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: key + order: 2 + size: + - 255 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + indices: [] + name: organisation_types + options: [] + order: 11 + organisations: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: organisations_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - type_id + match_type: '' + name: organisations_fk_type_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisation_types + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - social_type_id + match_type: '' + name: organisations_fk_social_type_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisation_social_types + type: FOREIGN KEY + fields: + country: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: country + order: 7 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_anchor: + data_type: boolean + default_value: !!perl/ref + =: FALSE + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_anchor + order: 17 + size: + - 0 + is_fair: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_fair + order: 11 + size: + - 0 + is_local: + data_type: boolean + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: is_local + order: 10 + size: + - 0 + latitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: latitude + order: 13 + size: + - 8 + - 5 + longitude: + data_type: decimal + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: longitude + order: 14 + size: + - 8 + - 5 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + pending: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: pending + order: 9 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + sector: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: sector + order: 8 + size: + - 1 + social_type_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: social_type_id + order: 16 + size: + - 0 + street_name: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: street_name + order: 4 + size: + - 0 + submitted_by_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: submitted_by_id + order: 12 + size: + - 0 + town: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: town + order: 5 + size: + - 255 + type_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: type_id + order: 15 + size: + - 0 + indices: + - fields: + - entity_id + name: organisations_idx_entity_id + options: [] + type: NORMAL + - fields: + - type_id + name: organisations_idx_type_id + options: [] + type: NORMAL + - fields: + - social_type_id + name: organisations_idx_social_type_id + options: [] + type: NORMAL + name: organisations + options: [] + order: 33 + organisations_external: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - external_reference_id + - external_id + match_type: '' + name: organisations_external_external_reference_id_external_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - external_reference_id + match_type: '' + name: organisations_external_fk_external_reference_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: external_references + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisations_external_fk_org_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + external_id: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_id + order: 4 + size: + - 255 + external_reference_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_reference_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + indices: + - fields: + - external_reference_id + name: organisations_external_idx_external_reference_id + options: [] + type: NORMAL + - fields: + - org_id + name: organisations_external_idx_org_id + options: [] + type: NORMAL + name: organisations_external + options: [] + order: 38 + session_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - token + match_type: '' + name: session_tokens_token + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: session_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: token + order: 2 + size: + - 255 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 3 + size: + - 0 + indices: + - fields: + - user_id + name: session_tokens_idx_user_id + options: [] + type: NORMAL + name: session_tokens + options: [] + order: 27 + topics: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - organisation_id + match_type: '' + name: topics_fk_organisation_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 200 + organisation_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: organisation_id + order: 2 + size: + - 0 + indices: + - fields: + - organisation_id + name: topics_idx_organisation_id + options: [] + type: NORMAL + name: topics + options: [] + order: 37 + transaction_category: + constraints: + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_transaction_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - category_id + match_type: '' + name: transaction_category_fk_category_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: category + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transaction_category_fk_transaction_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + category_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: category_id + order: 1 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - category_id + name: transaction_category_idx_category_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: transaction_category_idx_transaction_id + options: [] + type: NORMAL + name: transaction_category + options: [] + order: 34 + transaction_recurring: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transaction_recurring_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - category_id + match_type: '' + name: transaction_recurring_fk_category_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: category + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transaction_recurring_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + category_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: category_id + order: 9 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 8 + size: + - 15 + essential: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: essential + order: 7 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + last_updated: + data_type: datetime + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: last_updated + order: 6 + size: + - 0 + recurring_period: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: recurring_period + order: 10 + size: + - 255 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + start_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: start_time + order: 5 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transaction_recurring_idx_buyer_id + options: [] + type: NORMAL + - fields: + - category_id + name: transaction_recurring_idx_category_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transaction_recurring_idx_seller_id + options: [] + type: NORMAL + name: transaction_recurring + options: [] + order: 28 + transactions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transactions_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transactions_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + distance: + data_type: numeric + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: distance + order: 9 + size: + - 15 + essential: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: essential + order: 8 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + proof_image: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: proof_image + order: 5 + size: + - 0 + purchase_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_time + order: 7 + size: + - 0 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transactions_idx_buyer_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transactions_idx_seller_id + options: [] + type: NORMAL + name: transactions + options: [] + order: 18 + transactions_external: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - external_reference_id + - external_id + match_type: '' + name: transactions_external_external_reference_id_external_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - external_reference_id + match_type: '' + name: transactions_external_fk_external_reference_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: external_references + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transactions_external_fk_transaction_id + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + external_id: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_id + order: 4 + size: + - 255 + external_reference_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: external_reference_id + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - external_reference_id + name: transactions_external_idx_external_reference_id + options: [] + type: NORMAL + - fields: + - transaction_id + name: transactions_external_idx_transaction_id + options: [] + type: NORMAL + name: transactions_external + options: [] + order: 35 + transactions_meta: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - transaction_id + match_type: '' + name: transactions_meta_fk_transaction_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: transactions + type: FOREIGN KEY + fields: + business_tax_and_rebate: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: business_tax_and_rebate + order: 10 + size: + - 0 + central_loc_gov: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: central_loc_gov + order: 12 + size: + - 0 + gross_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_value + order: 5 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_service + order: 6 + size: + - 0 + national_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: national_service + order: 8 + size: + - 0 + net_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: net_value + order: 3 + size: + - 100 + - 0 + private_household_rebate: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: private_household_rebate + order: 9 + size: + - 0 + regional_service: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: regional_service + order: 7 + size: + - 0 + sales_tax_value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: sales_tax_value + order: 4 + size: + - 100 + - 0 + stat_loc_gov: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: stat_loc_gov + order: 11 + size: + - 0 + transaction_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: transaction_id + order: 2 + size: + - 0 + indices: + - fields: + - transaction_id + name: transactions_meta_idx_transaction_id + options: [] + type: NORMAL + name: transactions_meta + options: [] + order: 29 + user_topic_subscriptions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - topic_id + match_type: '' + name: user_topic_subscriptions_fk_topic_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: topics + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: user_topic_subscriptions_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + topic_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: topic_id + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + indices: + - fields: + - topic_id + name: user_topic_subscriptions_idx_topic_id + options: [] + type: NORMAL + - fields: + - user_id + name: user_topic_subscriptions_idx_user_id + options: [] + type: NORMAL + name: user_topic_subscriptions + options: [] + order: 39 + users: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: users_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: users_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 3 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_admin: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_admin + order: 6 + size: + - 0 + join_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: join_date + order: 4 + size: + - 0 + password: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: password + order: 5 + size: + - 100 + indices: + - fields: + - entity_id + name: users_idx_entity_id + options: [] + type: NORMAL + name: users + options: [] + order: 19 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - AccountToken + - Category + - Customer + - DeviceToken + - Entity + - EntityAssociation + - EntityPostcode + - ExternalReference + - Feedback + - GbPostcode + - GbWard + - GlobalMedalGroup + - GlobalMedals + - GlobalUserMedalProgress + - GlobalUserMedals + - ImportLookup + - ImportSet + - ImportValue + - Leaderboard + - LeaderboardSet + - LeaderboardValue + - OrgMedalGroup + - OrgMedals + - OrgUserMedalProgress + - OrgUserMedals + - Organisation + - OrganisationExternal + - OrganisationPayroll + - OrganisationSocialType + - OrganisationType + - SessionToken + - Topic + - Transaction + - TransactionCategory + - TransactionExternal + - TransactionMeta + - TransactionRecurring + - User + - UserTopicSubscription + - ViewQuantisedTransactionCategoryPg + - ViewQuantisedTransactionCategorySQLite + - ViewQuantisedTransactionPg + - ViewQuantisedTransactionSQLite + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 1.62 From def0cbb93a1adcdaf777d0b6d63e52b85abd3fc7 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Thu, 25 Mar 2021 13:53:49 +0000 Subject: [PATCH 286/289] Ignore NPM files --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7ffaa78..34e9971 100644 --- a/.gitignore +++ b/.gitignore @@ -15,8 +15,11 @@ cover_db/ schema.png etc/code-point-open/codepo_gb/ +postcode-data/*.csv pear-local_loop.production.conf localspend-47012.json -*postcodes.csv + +node_modules/ +package* From 5292540d1de658a196daa8874348747d2549c728 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Thu, 25 Mar 2021 13:54:04 +0000 Subject: [PATCH 287/289] Add channel creation, subscription --- lib/Pear/LocalLoop.pm | 2 + lib/Pear/LocalLoop/Command/dev_data.pm | 14 ++-- lib/Pear/LocalLoop/Controller/Api/Devices.pm | 12 --- lib/Pear/LocalLoop/Controller/Api/Topic.pm | 80 ++++++++++++++++++- lib/Pear/LocalLoop/Schema.pm | 2 +- .../LocalLoop/Schema/Result/DeviceToken.pm | 9 --- lib/Pear/LocalLoop/Schema/Result/Topic.pm | 10 ++- lib/Pear/LocalLoop/Schema/Result/User.pm | 8 ++ ...bscription.pm => UserTopicSubscription.pm} | 12 +-- 9 files changed, 109 insertions(+), 40 deletions(-) rename lib/Pear/LocalLoop/Schema/Result/{DeviceSubscription.pm => UserTopicSubscription.pm} (77%) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 38cc699..adaab03 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -213,6 +213,8 @@ sub startup { $api->post('/topic/add')->to('api-topic#create'); $api->post('/topics')->to('api-topic#get_all'); + $api->post('/topics/subscriptions')->to('api-topic#get_all_and_subscriptions'); + $api->post('/topics/update')->to('api-topic#update_subscriptions'); $api->post('/send-message')->to('api-sendmessage#post_message'); diff --git a/lib/Pear/LocalLoop/Command/dev_data.pm b/lib/Pear/LocalLoop/Command/dev_data.pm index 759a539..f8ff78c 100644 --- a/lib/Pear/LocalLoop/Command/dev_data.pm +++ b/lib/Pear/LocalLoop/Command/dev_data.pm @@ -25,7 +25,13 @@ sub run { } my $schema = $self->app->schema; - + + $c->schema->resultset('Topic')->create( + { + name => 'default' + } + ); + $schema->resultset('User')->create( { email => 'test@example.com', @@ -91,12 +97,6 @@ sub run { } ); - $c->schema->resultset('DeviceToken')->create( - { - name => 'default' - } - ); - return 1; } diff --git a/lib/Pear/LocalLoop/Controller/Api/Devices.pm b/lib/Pear/LocalLoop/Controller/Api/Devices.pm index c483b1f..90ae67b 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Devices.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Devices.pm @@ -89,18 +89,6 @@ sub create { my $response = $ua->request($request); if ( $response->is_success ) { - my $deviceToken = - $c->schema->resultset('DeviceToken')->find( { 'token' => $token } ); - my $topic = - $c->schema->resultset('Topic')->find( { 'name' => 'default' } ); - - $deviceToken->create_related( - 'device_subscriptions', - { - topic => $topic - } - ); - return $c->render( json => { success => Mojo::JSON->true, diff --git a/lib/Pear/LocalLoop/Controller/Api/Topic.pm b/lib/Pear/LocalLoop/Controller/Api/Topic.pm index 9bf7201..d38ed94 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Topic.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Topic.pm @@ -6,12 +6,21 @@ use JSON::Parse 'parse_json'; use Mojo::JWT; use Mojo::File; use Carp; +use Data::Dumper; has error_messages => sub { return { topic => { required => { message => 'Topic is required', status => 400 }, not_in_resultset => { message => 'Topic already exists', status => 400 }, + }, + token => { + required => { message => 'Device token is required', status => 400 }, + in_resultset => { message => 'Device token doesn\'t exist', status => 400 }, + }, + topicSubscriptions => { + required => { message => 'Set of topic subscriptions is required', status => 400 }, + in_resultset => { message => 'Topic doesn\'t exist', status => 400 }, } }; }; @@ -62,7 +71,7 @@ sub get_all { id => $_->id, name => $_->name, numberOfSubscribers => - $_->search_related( 'device_subscriptions', + $_->search_related( 'user_topic_subscriptions', { 'topic_id' => $_->id } )->count, } } $topic_rs->all @@ -75,4 +84,73 @@ sub get_all { } ); } + +sub get_all_and_subscriptions { + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + my $topic_rs = $c->schema->resultset('Topic'); + + my @topics = ( + map { + { + id => $_->id, + name => $_->name, + isSubscribed => $_->search_related( 'user_topic_subscriptions', + { 'topic_id' => $_->id, 'user_id' => $user->id })->count + } + } $topic_rs->all + ); + + return $c->render( + json => { + success => Mojo::JSON->true, + topics => \@topics, + } + ); +} + +sub update_subscriptions { + my $c = shift; + + my $user = $c->stash->{api_user}; + my $topic_rs = $c->schema->resultset('Topic'); + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->required('topicSubscriptions'); + + foreach my $sub ( @{ $validation->every_param('topicSubscriptions') } ) { + my $subscription = $user->find_related( 'user_topic_subscriptions', + { 'topic_id' => $sub->{id} } + ); + + if ( $sub->{isSubscribed} && !$subscription ) { + $user->create_related( + 'user_topic_subscriptions', + { + topic_id => $sub->{id}, + } + ); + } elsif ( !$sub->{isSubscribed} && $subscription ) { + $user->delete_related( + 'user_topic_subscriptions', + { + topic_id => $sub->{id}, + } + ); + } + } + + return $c->render( + json => { + success => Mojo::JSON->true, + message => 'Topic subscriptions updated successfully!', + } + ); +} + 1; diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index 17cb9cf..7c78743 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -6,7 +6,7 @@ use warnings; use base 'DBIx::Class::Schema'; -our $VERSION = 34; +our $VERSION = 35; __PACKAGE__->load_namespaces; diff --git a/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm b/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm index e97e87e..427ac38 100644 --- a/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm +++ b/lib/Pear/LocalLoop/Schema/Result/DeviceToken.pm @@ -46,13 +46,4 @@ __PACKAGE__->belongs_to( { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); -__PACKAGE__->has_many( - "device_subscriptions", - "Pear::LocalLoop::Schema::Result::DeviceSubscription", - { "foreign.device_token_id" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, -); - -__PACKAGE__->many_to_many( 'topics' => 'device_subscriptions', 'topic' ); - 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Topic.pm b/lib/Pear/LocalLoop/Schema/Result/Topic.pm index 434ae62..b5615d5 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Topic.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Topic.pm @@ -43,15 +43,17 @@ __PACKAGE__->belongs_to( ); __PACKAGE__->has_many( - "device_subscriptions", - "Pear::LocalLoop::Schema::Result::DeviceSubscription", + "user_topic_subscriptions", + "Pear::LocalLoop::Schema::Result::UserTopicSubscription", { "foreign.topic_id" => "self.id" }, { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->many_to_many( - 'device_tokens' => 'device_subscriptions', - 'device_token' + 'users' => 'user_topic_subscriptions', + 'user' ); +__PACKAGE__->many_to_many( 'topics' => 'user_topic_subscriptions', 'topic' ); + 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/User.pm b/lib/Pear/LocalLoop/Schema/Result/User.pm index 0ac7615..01dd8a7 100644 --- a/lib/Pear/LocalLoop/Schema/Result/User.pm +++ b/lib/Pear/LocalLoop/Schema/Result/User.pm @@ -84,6 +84,14 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); +__PACKAGE__->has_many( + "user_topic_subscriptions", + "Pear::LocalLoop::Schema::Result::UserTopicSubscription", + { "foreign.user_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + + __PACKAGE__->filter_column( is_admin => { filter_to_storage => 'to_bool', diff --git a/lib/Pear/LocalLoop/Schema/Result/DeviceSubscription.pm b/lib/Pear/LocalLoop/Schema/Result/UserTopicSubscription.pm similarity index 77% rename from lib/Pear/LocalLoop/Schema/Result/DeviceSubscription.pm rename to lib/Pear/LocalLoop/Schema/Result/UserTopicSubscription.pm index 594eeba..6517c1d 100644 --- a/lib/Pear/LocalLoop/Schema/Result/DeviceSubscription.pm +++ b/lib/Pear/LocalLoop/Schema/Result/UserTopicSubscription.pm @@ -1,11 +1,11 @@ -package Pear::LocalLoop::Schema::Result::DeviceSubscription; +package Pear::LocalLoop::Schema::Result::UserTopicSubscription; use strict; use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->table("device_subscriptions"); +__PACKAGE__->table("user_topic_subscriptions"); __PACKAGE__->add_columns( "id" => { @@ -13,7 +13,7 @@ __PACKAGE__->add_columns( is_auto_increment => 1, is_nullable => 0, }, - "device_token_id" => { + "user_id" => { data_type => "integer", is_foreign_key => 1, is_nullable => 0, @@ -28,9 +28,9 @@ __PACKAGE__->add_columns( __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "device_token", - "Pear::LocalLoop::Schema::Result::DeviceToken", - "device_token_id", + "user", + "Pear::LocalLoop::Schema::Result::User", + "user_id", { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); From f483cc2818c840db2b9f3d8c4e33a1b9510ef6e3 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Thu, 25 Mar 2021 13:54:14 +0000 Subject: [PATCH 288/289] Add topic and device token tests --- t/api/device_tokens.t | 109 +++++++++++++++++++++++++++++++++++ t/api/topics.t | 130 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 t/api/device_tokens.t create mode 100644 t/api/topics.t diff --git a/t/api/device_tokens.t b/t/api/device_tokens.t new file mode 100644 index 0000000..1e80ccc --- /dev/null +++ b/t/api/device_tokens.t @@ -0,0 +1,109 @@ +use Mojo::Base -strict; + +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; + +my $session_key = $framework->login({ + email => 'test1@example.com', + password => 'abc123', +}); + +my $token = 'd-ukAXXVWudTtDg1q2kHY6:APA91bEfTE3VGB0EjDuVA0QX5XMTrQU4szYWv64LpV9_VUD4zfL7SKEKLd0gnm0yPPPcWaol-PcADVkfXQCmQKLMhVnqTSVs1MzGv0j_6bpWb0Rrqnv63umFbv99jZV8rEgIfSjsbMki'; + +## Device Tokens + +#No JSON sent +$t->post_ok('/api/device-token/check') + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/JSON is missing/i); + +#Empty JSON +$t->post_ok('/api/device-token/check' => json => {}) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false); + +#No session key +$t->post_ok('/api/device-token/check' => json => { + token => $token + }) + ->status_is(401) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Invalid Session/); + +#Non-existent token +$t->post_ok('/api/device-token/check' => json => { + session_key => $session_key, + token => $token + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/exists', Mojo::JSON->false); + +#TODO: add a check for a real token + +#No JSON sent +$t->post_ok('/api/device-token/add') + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/JSON is missing/i); + +#Empty JSON +$t->post_ok('/api/device-token/add' => json => {}) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false); + +#No session key +$t->post_ok('/api/device-token/add' => json => { + token => $token, + email => 'test@test.com' + }) + ->status_is(401) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Invalid Session/); + +#Non-existent token +$t->post_ok('/api/device-token/add' => json => { + session_key => $session_key, + token => $token, + email => 'test1@example.com' + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->true); + +#TODO: add a check for a real token + +#No JSON sent +$t->post_ok('/api/device-tokens') + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/JSON is missing/i); + +#Empty JSON +$t->post_ok('/api/device-tokens' => json => {}) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false); + +#Non-existent token +$t->post_ok('/api/device-tokens' => json => { + session_key => $session_key, + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->true); + +#TODO: add a check for a real token + +$framework->logout( $session_key ); + +done_testing; diff --git a/t/api/topics.t b/t/api/topics.t new file mode 100644 index 0000000..044b9c6 --- /dev/null +++ b/t/api/topics.t @@ -0,0 +1,130 @@ +use Mojo::Base -strict; + +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; + +my $session_key = $framework->login({ + email => 'org@example.com', + password => 'abc123', +}); + +## Topics + +#No JSON sent +$t->post_ok('/api/topic/add') + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/JSON is missing/i); + +#Empty JSON +$t->post_ok('/api/topic/add' => json => {}) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false); + +#No session key +$t->post_ok('/api/topic/add' => json => { + topic => 'test', + }) + ->status_is(401) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Invalid Session/); + +#Create new topic +$t->post_ok('/api/topic/add' => json => { + session_key => $session_key, + topic => 'test', + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->true); + +#No JSON sent +$t->post_ok('/api/topics') + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/JSON is missing/i); + +#Empty JSON +$t->post_ok('/api/topics' => json => {}) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false); + +#Get all topics +$t->post_ok('/api/topics' => json => { + session_key => $session_key + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->true); + +#No JSON sent +$t->post_ok('/api/topics/subscriptions') + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/JSON is missing/i); + +#Empty JSON +$t->post_ok('/api/topics/subscriptions' => json => {}) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false); + +#Get all subscriptions +$t->post_ok('/api/topics/subscriptions' => json => { + session_key => $session_key, + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->true); + +#No JSON sent +$t->post_ok('/api/topics/update') + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/JSON is missing/i); + +#Empty JSON +$t->post_ok('/api/topics/update' => json => {}) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false); + +#No session key +$t->post_ok('/api/topics/update' => json => { + topicSubscriptions => [ + { + id => 1, + name => 'test', + isSubscribed => Mojo::JSON->true, + } + ], + }) + ->status_is(401) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Invalid Session/); + +#Create new topic +$t->post_ok('/api/topics/update' => json => { + session_key => $session_key, + topicSubscriptions => [ + { + id => 1, + name => 'test', + isSubscribed => Mojo::JSON->true, + } + ], + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->true); + + +$framework->logout( $session_key ); + +done_testing; From cc6a59d49a6768261fbc6c4ce94d42da5035f806 Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Thu, 25 Mar 2021 14:19:47 +0000 Subject: [PATCH 289/289] Add JSON::Parse dep --- cpanfile | 1 + 1 file changed, 1 insertion(+) diff --git a/cpanfile b/cpanfile index 8c2d742..84a9032 100644 --- a/cpanfile +++ b/cpanfile @@ -2,6 +2,7 @@ requires 'Mojolicious'; requires 'Mojolicious::Plugin::Authentication'; requires 'Data::UUID'; requires 'Devel::Dwarn'; +requires 'JSON::Parse'; requires 'Mojo::JSON'; requires 'LWP::UserAgent'; requires 'Mojo::JWT';