Add code formatter, format all code

This commit is contained in:
Rumperuu 2021-03-20 12:09:50 +00:00
parent 602a59f1c3
commit 47a55f6322
120 changed files with 8061 additions and 6967 deletions

View file

@ -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;
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') || '{}' );
# 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;
}
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;
my $c = shift;
return $c->render(
json => {
success => Mojo::JSON->true,
message => 'Database connection successful',
},
status => 200,
);
return $c->render(
json => {
success => Mojo::JSON->true,
message => 'Database connection successful',
},
status => 200,
);
}
sub post_login {
my $c = shift;
my $c = shift;
my $validation = $c->validation;
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
$validation->required('email')->email;
$validation->required('password');
$validation->input( $c->stash->{api_json} );
$validation->required('email')->email;
$validation->required('password');
return $c->api_validation_error if $validation->has_error;
return $c->api_validation_error if $validation->has_error;
my $email = $validation->param('email');
my $password = $validation->param('password');
my $email = $validation->param('email');
my $password = $validation->param('password');
$c->app->log->debug( __PACKAGE__ . " login attempt for [" . $email . "]" );
$c->app->log->debug( __PACKAGE__ . " login attempt for [" . $email . "]" );
my $user_result = $c->schema->resultset('User')->find({ email => $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;
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->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;

View file

@ -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 / ],
{
columns => [
{
quantised => 'quantised_weeks',
value => { sum => 'value' },
category_id => 'category_id',
essential => 'essential',
},
],
group_by => [qw/ category_id quantised_weeks essential /],
}
);
my $data = { categories => {}, essentials => {} };
my $category_list = $c->schema->resultset('Category')->as_hash;
for my $cat_trans ( $month_transaction_category_rs->all ) {
my $quantised = $c->db_datetime_parser->parse_datetime(
$cat_trans->get_column('quantised') );
my $days = $c->format_iso_date($quantised) || 0;
my $category = $cat_trans->get_column('category_id') || 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 $data = { categories => {}, essentials => {} };
my $category_list = $c->schema->resultset('Category')->as_hash;
for my $cat_trans ( $month_transaction_category_rs->all ) {
my $quantised = $c->db_datetime_parser->parse_datetime($cat_trans->get_column('quantised'));
my $days = $c->format_iso_date( $quantised ) || 0;
my $category = $cat_trans->get_column('category_id') || 0;
my $value = ($cat_trans->get_column('value') || 0) / 100000;
$data->{categories}->{$days}->{$category_list->{$category}} += $value;
next unless $cat_trans->get_column('essential');
$data->{essentials}->{$days}->{value} += $value;
}
for my $day ( keys %{ $data->{categories} } ) {
my @days = ( map{ {
days => $day,
value => $data->{categories}->{$day}->{$_},
category => $_,
} } keys %{ $data->{categories}->{$day} } );
$data->{categories}->{$day} = [ sort { $b->{value} <=> $a->{value} } @days ];
}
return $c->render(
json => {
success => Mojo::JSON->true,
data => $data,
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;

View file

@ -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 $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 );
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
return $c->api_validation_error if $validation->has_error;
my $token_rs = $c->schema->resultset('DeviceToken');
my $user_rs = $c->schema->resultset('User');
my $user = $user_rs->find({'email' => $validation->param('email')});
my $token = $validation->param('token');
# 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 );
$user->create_related(
'device_tokens',
{
token => $token,
}
);
my $end_point = "https://iid.googleapis.com/iid/v1/${token}/rel/topics/default";
return $c->api_validation_error if $validation->has_error;
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 $user = $user_rs->find( { 'email' => $validation->param('email') } );
my $ua = LWP::UserAgent->new();
my $request = HTTP::Request->new('POST', $end_point);
my $token = $validation->param('token');
$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
}
$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 $c = shift;
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 $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;

View file

@ -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' },
});
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
);
# 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,
});
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 $c = shift;
my $user = $c->stash->{api_user};
my $user = $c->stash->{api_user};
# TODO give an error if user is not of Lancashire County Council
# TODO give an error if user is not of Lancashire County Council
# my $is_lcc = $user->entity->organisation->count({ name => "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 $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;
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' => [
{
'sum' => 'sales.value',
'-as' => 'total_spend',
}
],
'+as' => [ 'total_spend' ],
page => $v->param('page') || 1,
rows => 10,
order_by => $order_by,
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 @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->api_validation_error if $v->has_error;
return $c->render(json => {
success => Mojo::JSON->true,
suppliers => \@supplier_list,
page_no => $lcc_suppliers->pager->total_entries,
});
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' => [
{
'sum' => 'sales.value',
'-as' => 'total_spend',
}
],
'+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,
}
);
}
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(
{
quantised => 'quantised_days',
count => \"COUNT(*)",
total_spend => { sum => 'value' },
purchase_time => {
-between => [
$dtf->format_datetime($first),
$dtf->format_datetime($last),
],
},
buyer_id => $user->entity->id,
},
{
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,
);
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,
});
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 $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,
);
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,
});
return $c->render(
json => {
success => Mojo::JSON->true,
data => \@graph_data,
}
);
}
sub post_supplier_history {
my $c = shift;
my $c = shift;
my $user = $c->stash->{api_user};
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);
# 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 $dtf = $c->schema->storage->datetime_parser;
my $year_rs = $c->schema->resultset('Entity')->search(
{
id => 'me.id',
name => 'organisation.name',
count => \"COUNT(*)",
total_spend => { sum => 'sales.value' },
}
],
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 => [
'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 $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 $half_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($second),
$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 $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 => [
{
id => 'me.id',
name => 'organisation.name',
count => \"COUNT(*)",
total_spend => { sum => 'sales.value' },
}
],
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,
};
}
);
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 ($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') } },
};
}
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 ],
});
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;
{
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/],
}
);
$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 $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
);
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,
});
return $c->render(
json => {
success => Mojo::JSON->true,
wards => \@ward_transaction_list,
types => $transaction_type_data,
}
);
}
1;

View file

@ -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;

View file

@ -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 $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->optional('page')->number;
return $c->api_validation_error if $validation->has_error;
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' },
},
);
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
);
# 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,
});
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 $c = shift;
my $user = $c->stash->{api_user};
my $user = $c->stash->{api_user};
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
return $c->api_validation_error if $validation->has_error;
return $c->api_validation_error if $validation->has_error;
my $user_rs = $c->schema->resultset('User')->search({
id => { "!=" => $user->id },
});
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');
$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;
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');
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,
});
});
$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',
});
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 $c = shift;
my $user = $c->stash->{api_user};
my $user = $c->stash->{api_user};
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
return $c->api_validation_error if $validation->has_error;
return $c->api_validation_error if $validation->has_error;
my $user_rs = $c->schema->resultset('User')->search({
id => { "!=" => $user->id },
});
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');
$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;
return $c->api_validation_error if $validation->has_error;
$c->schema->txn_do( sub {
$user->entity->organisation->update({
entry_period => $validation->param('entry_period'),
});
});
$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',
});
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 $c = shift;
my $user = $c->stash->{api_user};
my $user = $c->stash->{api_user};
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
return $c->api_validation_error if $validation->has_error;
return $c->api_validation_error if $validation->has_error;
my $user_rs = $c->schema->resultset('User')->search({
id => { "!=" => $user->id },
});
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');
$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;
return $c->api_validation_error if $validation->has_error;
$c->schema->txn_do( sub {
$user->entity->organisation->update({
entry_period => $validation->param('entry_period'),
});
});
$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',
});
return $c->render(
json => {
success => Mojo::JSON->true,
message => 'Submitted Employee Info Successfully',
}
);
}
1;

View file

@ -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 },
},
};
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 $c = shift;
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
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 $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');
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');
$validation->required('postcode')->postcode;
$validation->required('usertype')->in( 'customer', 'organisation' );
my $usertype = $validation->param('usertype') || '';
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');
}
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;
return $c->api_validation_error if $validation->has_error;
my $location = $c->get_location_from_postcode(
$validation->param('postcode'),
$usertype,
);
my $location =
$c->get_location_from_postcode( $validation->param('postcode'),
$usertype, );
if ($usertype eq 'customer'){
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->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',
});
});
$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') {
}
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',
});
});
}
$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',
});
return $c->render(
json => {
success => Mojo::JSON->true,
message => 'Registered Successfully',
}
);
}
1;

View file

@ -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);
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});
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;
$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 $c = shift;
my $topic_rs = $c->schema->resultset('Topic');
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
);
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,
});
return $c->render(
json => {
success => Mojo::JSON->true,
topics => \@topics,
}
);
}
sub post_message {
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('devicetokens')->in_resultset('token', $c->schema->resultset('DeviceToken'));
$validation->required('topic');
$validation->required('sender')->in_resultset('name', $c->schema->resultset('Organisation'));
$validation->required('messagetext');
#$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;
return $c->api_validation_error if $validation->has_error;
my $end_point = "https://fcm.googleapis.com/v1/projects/localspend-47012/messages:send";
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');
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);
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,
$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);
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;

File diff suppressed because it is too large Load diff

View file

@ -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 $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->optional('page')->number;
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 $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,
});
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,
)),
# 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
);
}
} $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 @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,
});
return $c->render(
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 $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,
);
}
$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'),
}
);
}
);
}
$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',
});
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,
);
}
$recur_transaction->delete;
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,
message => 'Recurring Transaction Deleted Successfully',
}
);
}
$recur_transaction->delete;
return $c->render( json => {
success => Mojo::JSON->true,
message => 'Recurring Transaction Deleted Successfully',
});
}

View file

@ -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');
# First pass of required items
return $c->api_validation_error if $validation->has_error;
my $type = $validation->param('transaction_type');
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 );
#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;
$organisation = $valid_org_rs->find( $validation->param('organisation_id') );
my $type = $validation->param('transaction_type');
} 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 );
my $organisation;
return $c->api_validation_error if $validation->has_error;
if ( $type == 1 ) {
$organisation = $valid_org_rs->find( $validation->param('organisation_id') );
# 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 );
} 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',
);
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,
);
}
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,
}
);
elsif ( $type == 2 ) {
unless ( defined $new_transaction ) {
return $c->render(
json => {
success => Mojo::JSON->false,
message => 'Error Adding Transaction',
error => 'transaction_error',
},
status => 400,
# 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 );
return $c->api_validation_error if $validation->has_error;
$organisation =
$valid_org_rs->find( $validation->param('organisation_id') );
}
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;
}
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,
}
);
}
if ( defined $category ) {
$c->schema->resultset('TransactionCategory')->create({
category_id => $category,
transaction_id => $new_transaction->id,
});
}
unless ( defined $new_transaction ) {
return $c->render(
json => {
success => Mojo::JSON->false,
message => 'Error Adding Transaction',
error => 'transaction_error',
},
status => 400,
);
}
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,
});
}
if ( defined $category ) {
$c->schema->resultset('TransactionCategory')->create(
{
category_id => $category,
transaction_id => $new_transaction->id,
}
);
}
return $c->render( json => {
success => Mojo::JSON->true,
message => 'Upload Successful',
});
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 $c = shift;
my $self = $c;
my $user = $c->stash->{api_user};
my $user = $c->stash->{api_user};
my $validation = $c->validation;
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
$validation->input( $c->stash->{api_json} );
$validation->required('search_name');
$validation->optional('page')->number;
$validation->required('search_name');
$validation->optional('page')->number;
return $c->api_validation_error if $validation->has_error;
return $c->api_validation_error if $validation->has_error;
my $search_name = $validation->param('search_name');
my $search_name = $validation->param('search_name');
my $search_stmt = [ 'LOWER("name") LIKE ?', '%' . lc $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 $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 $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 @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
);
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,
});
return $self->render(
json => {
success => Mojo::JSON->true,
validated => \@valid_orgs,
unvalidated => \@pending_orgs,
}
);
}
1;

View file

@ -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 $c = shift;
my $user = $c->stash->{api_user};
my $user_result = $c->schema->resultset('User')->find({ id => $c->stash->{api_user}->id });
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 ( 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
);
}
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 => '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_account_update {
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('password');
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
$validation->required('password');
return $c->api_validation_error if $validation->has_error;
return $c->api_validation_error if $validation->has_error;
if ( ! $user->check_password($validation->param('password')) ) {
return $c->render(
json => {
success => Mojo::JSON->false,
message => 'password is invalid.',
},
status => 401
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 },
}
);
}
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');
$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');
}
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;
return $c->api_validation_error if $validation->has_error;
my $location =
$c->get_location_from_postcode( $validation->param('postcode'),
$user->type, );
my $location = $c->get_location_from_postcode(
$validation->param('postcode'),
$user->type,
);
if ( $user->type eq 'customer' ) {
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') )
: ()
),
}
);
}
);
$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' ) {
}
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') )
: ()
),
}
);
}
);
}
$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',
});
return $c->render(
json => {
success => Mojo::JSON->true,
message => 'Edited Account Successfully',
}
);
}
1;

View file

@ -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;

View file

@ -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
/ );
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 $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->$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_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 ( $c, $day_duration ) = @_;
my $duration = DateTime::Duration->new( days => $day_duration );
my $entity = $c->stash->{api_user}->entity;
my $duration = DateTime::Duration->new( days => $day_duration );
my $entity = $c->stash->{api_user}->entity;
my $data = { labels => [], data => [] };
my $data = { labels => [], data => [] };
my ( $start, $end ) = $c->_get_start_end_duration( $duration );
my ( $start, $end ) = $c->_get_start_end_duration($duration);
$data->{bounds} = {
min => $c->format_iso_datetime( $start ),
max => $c->format_iso_datetime( $end ),
};
$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,
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 ( $c, $day_duration ) = @_;
my $duration = DateTime::Duration->new( days => $day_duration );
my $entity = $c->stash->{api_user}->entity;
my $duration = DateTime::Duration->new( days => $day_duration );
my $entity = $c->stash->{api_user}->entity;
my $data = { labels => [], data => [] };
my $data = { labels => [], data => [] };
my ( $start, $end ) = $c->_get_start_end_duration( $duration );
my ( $start, $end ) = $c->_get_start_end_duration($duration);
$data->{bounds} = {
min => $c->format_iso_datetime( $start ),
max => $c->format_iso_datetime( $end ),
};
$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 $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 ( $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;

View file

@ -2,61 +2,68 @@ package Pear::LocalLoop::Controller::Api::V1::Customer::Pies;
use Mojo::Base 'Mojolicious::Controller';
sub index {
my $c = shift;
my $c = shift;
my $entity = $c->stash->{api_user}->entity;
my $entity = $c->stash->{api_user}->entity;
my $purchase_rs = $entity->purchases;
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_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 $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_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 $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,
};
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,
}
);
return $c->render(
json => {
success => Mojo::JSON->true,
local_all => $local_all,
}
);
}

View file

@ -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,
}
);
}

View file

@ -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;

View file

@ -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 $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 $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 $c = shift;
my $validation = $c->validation;
$validation->input( $c->stash->{api_json} );
$validation->required('start')->is_iso_date;
$validation->required('end')->is_iso_date;
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;
return $c->api_validation_error if $validation->has_error;
my $entity = $c->stash->{api_user}->entity;
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') );
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,
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 ( $c, $day_duration ) = @_;
my $duration = DateTime::Duration->new( days => $day_duration );
my $entity = $c->stash->{api_user}->entity;
my $duration = DateTime::Duration->new( days => $day_duration );
my $entity = $c->stash->{api_user}->entity;
my $data = { labels => [], data => [] };
my $data = { labels => [], data => [] };
my ( $start, $end ) = $c->_get_start_end_duration( $duration );
my ( $start, $end ) = $c->_get_start_end_duration($duration);
$data->{bounds} = {
min => $c->format_iso_datetime( $start ),
max => $c->format_iso_datetime( $end ),
};
$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,
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 ( $c, $day_duration ) = @_;
my $duration = DateTime::Duration->new( days => $day_duration );
my $entity = $c->stash->{api_user}->entity;
my $duration = DateTime::Duration->new( days => $day_duration );
my $entity = $c->stash->{api_user}->entity;
my $data = { labels => [], data => [] };
my $data = { labels => [], data => [] };
my ( $start, $end ) = $c->_get_start_end_duration( $duration );
my ( $start, $end ) = $c->_get_start_end_duration($duration);
$data->{bounds} = {
min => $c->format_iso_datetime( $start ),
max => $c->format_iso_datetime( $end ),
};
$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,
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 ( $c, $day_duration ) = @_;
my $duration = DateTime::Duration->new( days => $day_duration );
my $entity = $c->stash->{api_user}->entity;
my $duration = DateTime::Duration->new( days => $day_duration );
my $entity = $c->stash->{api_user}->entity;
my $data = { labels => [], data => [] };
my $data = { labels => [], data => [] };
my ( $start, $end ) = $c->_get_start_end_duration( $duration );
my ( $start, $end ) = $c->_get_start_end_duration($duration);
$data->{bounds} = {
min => $c->format_iso_datetime( $start ),
max => $c->format_iso_datetime( $end ),
};
$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,
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;

View file

@ -2,61 +2,68 @@ package Pear::LocalLoop::Controller::Api::V1::Organisation::Pies;
use Mojo::Base 'Mojolicious::Controller';
sub index {
my $c = shift;
my $c = shift;
my $entity = $c->stash->{api_user}->entity;
my $entity = $c->stash->{api_user}->entity;
my $purchase_rs = $entity->purchases;
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_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 $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_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 $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,
};
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,
}
);
return $c->render(
json => {
success => Mojo::JSON->true,
local_all => $local_all,
}
);
}

View file

@ -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,
}
);
}

View file

@ -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' } },
],
},
};
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,
},
}
}
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;

View file

@ -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;

View file

@ -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;