From 662219fc6e4bc2429d92fb00b865ebe6eb415daf Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 8 Sep 2017 11:41:21 +0100 Subject: [PATCH 01/15] Initial API for submission added --- lib/Pear/LocalLoop.pm | 3 + .../LocalLoop/Controller/Api/Organisation.pm | 120 ++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 lib/Pear/LocalLoop/Controller/Api/Organisation.pm diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 18e997b..fbc6d74 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -155,6 +155,9 @@ sub startup { $api->post('/stats')->to('api-stats#post_index'); $api->post('/stats/leaderboard')->to('api-stats#post_leaderboards'); $api->post('/outgoing-transactions')->to('api-transactions#post_transaction_list_purchases'); + $api->post('/org/payroll')->to('api-organisation#post_payroll'); + $api->post('/org/supplier')->to('api-organisation#post_supplier'); + $api->post('/org/employee')->to('api-organisation#post_employee'); my $api_v1 = $api->under('/v1'); diff --git a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm new file mode 100644 index 0000000..90edbc2 --- /dev/null +++ b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm @@ -0,0 +1,120 @@ +package Pear::LocalLoop::Controller::Api::Organisation; +use Mojo::Base 'Mojolicious::Controller'; +use Mojo::JSON; + +has error_messages => sub { + return { + sector => { + required => { message => 'No sector sent.', status => 400 }, + }, + }; +}; + +sub post_payroll { + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + return $c->api_validation_error if $validation->has_error; + + my $user_rs = $c->schema->resultset('User')->search({ + id => { "!=" => $user->id }, + }); + + $validation->required('entryperiod'); + $validation->required('employeeamount'); + $validation->required('localemployeeamount'); + $validation->required('grosspayroll'); + $validation->optional('payrollincometax'); + $validation->optional('payrollemployeeni'); + $validation->optional('payrollemployerni'); + $validation->optional('payrolltotalpension'); + $validation->optional('payrollotherbenefit'); + + return $c->api_validation_error if $validation->has_error; + + $c->schema->txn_do( sub { + $user->entity->organisation->update({ + entry_period => $validation->param('entryperiod'), + }); + }); + + return $c->render( json => { + success => Mojo::JSON->true, + message => 'Submitted Payroll Info Successfully', + }); +} + +sub post_supplier { + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + return $c->api_validation_error if $validation->has_error; + + my $user_rs = $c->schema->resultset('User')->search({ + id => { "!=" => $user->id }, + }); + + $validation->required('entryperiod'); + $validation->optional('postcode')->postcode; + $validation->optional('supplierbusinessname'); + $validation->optional('monthlyspend'); + + return $c->api_validation_error if $validation->has_error; + + $c->schema->txn_do( sub { + $user->entity->organisation->update({ + entry_period => $validation->param('entryperiod'), + }); + }); + + return $c->render( json => { + success => Mojo::JSON->true, + message => 'Submitted Payroll Info Successfully', + }); +} + +sub post_employee { + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + + return $c->api_validation_error if $validation->has_error; + + my $user_rs = $c->schema->resultset('User')->search({ + id => { "!=" => $user->id }, + }); + + $validation->required('entryperiod'); + $validation->optional('employeeno'); + $validation->optional('employeeincometax'); + $validation->optional('employeegrosswage'); + $validation->optional('employeeni'); + $validation->optional('employeepension'); + $validation->optional('employeeotherbenefit'); + + return $c->api_validation_error if $validation->has_error; + + $c->schema->txn_do( sub { + $user->entity->organisation->update({ + entry_period => $validation->param('entryperiod'), + }); + }); + + return $c->render( json => { + success => Mojo::JSON->true, + message => 'Submitted Payroll Info Successfully', + }); +} + +1; From 9cfd5536b93d79d98b5054b5e8408f19c055a65e Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 8 Sep 2017 12:15:11 +0100 Subject: [PATCH 02/15] Removed redundant code and added error messages --- .../LocalLoop/Controller/Api/Organisation.pm | 88 +++++++++++++++---- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 1 - 2 files changed, 70 insertions(+), 19 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm index 90edbc2..375f13f 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm @@ -4,8 +4,60 @@ use Mojo::JSON; has error_messages => sub { return { - sector => { - required => { message => 'No sector sent.', status => 400 }, + entryperiod => { + required => { message => 'No entry period sent.', status => 400 }, + }, + employeeamount => { + required => { message => 'No employee amount sent.', status => 400 }, + }, + localemployeeamount => { + required => { message => 'No local employee amount sent.', status => 400 }, + }, + grosspayroll => { + required => { message => 'No gross payroll sent.', status => 400 }, + }, + payrollincometax => { + required => { message => 'no payroll income tax sent.', status => 400 }, + }, + payrollemployeeni => { + required => { message => 'no payroll employee ni sent.', status => 400 }, + }, + payrollemployerni => { + required => { message => 'no payroll employer ni sent.', status => 400 }, + }, + payrolltotalpension => { + required => { message => 'no payroll total pension sent.', status => 400 }, + }, + payrollotherbenefit => { + required => { message => 'no payroll other benefit sent.', status => 400 }, + }, + supplierbusinessname => { + 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 }, + }, + monthlyspend => { + required => { message => 'no monthly spend sent.', status => 400 }, + }, + employeeno => { + required => { message => 'no employee no sent.', status => 400 }, + }, + employeeincometax => { + required => { message => 'no employee income tax sent.', status => 400 }, + }, + employeegrosswage => { + required => { message => 'no employee gross wage sent.', status => 400 }, + }, + employeeni => { + required => { message => 'no employee ni sent.', status => 400 }, + }, + employeepension => { + required => { message => 'no employee pension sent.', status => 400 }, + }, + employeeotherbenefit => { + required => { message => 'no employee other benefits sent.', status => 400 }, }, }; }; @@ -28,11 +80,11 @@ sub post_payroll { $validation->required('employeeamount'); $validation->required('localemployeeamount'); $validation->required('grosspayroll'); - $validation->optional('payrollincometax'); - $validation->optional('payrollemployeeni'); - $validation->optional('payrollemployerni'); - $validation->optional('payrolltotalpension'); - $validation->optional('payrollotherbenefit'); + $validation->required('payrollincometax'); + $validation->required('payrollemployeeni'); + $validation->required('payrollemployerni'); + $validation->required('payrolltotalpension'); + $validation->required('payrollotherbenefit'); return $c->api_validation_error if $validation->has_error; @@ -63,9 +115,9 @@ sub post_supplier { }); $validation->required('entryperiod'); - $validation->optional('postcode')->postcode; - $validation->optional('supplierbusinessname'); - $validation->optional('monthlyspend'); + $validation->required('postcode')->postcode; + $validation->required('supplierbusinessname'); + $validation->required('monthlyspend'); return $c->api_validation_error if $validation->has_error; @@ -77,7 +129,7 @@ sub post_supplier { return $c->render( json => { success => Mojo::JSON->true, - message => 'Submitted Payroll Info Successfully', + message => 'Submitted Supplier Info Successfully', }); } @@ -96,12 +148,12 @@ sub post_employee { }); $validation->required('entryperiod'); - $validation->optional('employeeno'); - $validation->optional('employeeincometax'); - $validation->optional('employeegrosswage'); - $validation->optional('employeeni'); - $validation->optional('employeepension'); - $validation->optional('employeeotherbenefit'); + $validation->required('employeeno'); + $validation->required('employeeincometax'); + $validation->required('employeegrosswage'); + $validation->required('employeeni'); + $validation->required('employeepension'); + $validation->required('employeeotherbenefit'); return $c->api_validation_error if $validation->has_error; @@ -113,7 +165,7 @@ sub post_employee { return $c->render( json => { success => Mojo::JSON->true, - message => 'Submitted Payroll Info Successfully', + message => 'Submitted Employee Info Successfully', }); } diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index 7b037d5..81fc5af 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -79,7 +79,6 @@ has error_messages => sub { required => { message => 'search_name is missing', status => 400 }, }, postcode => { - required => { message => 'postcode is missing', status => 400 }, postcode => { message => 'postcode must be valid', status => 400 }, }, }; From 26a37904d207951451359ef390f3726a651b3842 Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 8 Sep 2017 13:00:42 +0100 Subject: [PATCH 03/15] Naming sanitised --- .../LocalLoop/Controller/Api/Organisation.pm | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm index 375f13f..ce04ce4 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm @@ -4,59 +4,59 @@ use Mojo::JSON; has error_messages => sub { return { - entryperiod => { + entry_period => { required => { message => 'No entry period sent.', status => 400 }, }, - employeeamount => { + employee_amount => { required => { message => 'No employee amount sent.', status => 400 }, }, - localemployeeamount => { + local_employee_amount => { required => { message => 'No local employee amount sent.', status => 400 }, }, - grosspayroll => { + gross_payroll => { required => { message => 'No gross payroll sent.', status => 400 }, }, - payrollincometax => { + payroll_income_tax => { required => { message => 'no payroll income tax sent.', status => 400 }, }, - payrollemployeeni => { + payroll_employee_ni => { required => { message => 'no payroll employee ni sent.', status => 400 }, }, - payrollemployerni => { + payroll_employer_ni => { required => { message => 'no payroll employer ni sent.', status => 400 }, }, - payrolltotalpension => { + payroll_total_pension => { required => { message => 'no payroll total pension sent.', status => 400 }, }, - payrollotherbenefit => { + payroll_other_benefit => { required => { message => 'no payroll other benefit sent.', status => 400 }, }, - supplierbusinessname => { + 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 }, }, - monthlyspend => { + monthly_spend => { required => { message => 'no monthly spend sent.', status => 400 }, }, - employeeno => { + employee_no => { required => { message => 'no employee no sent.', status => 400 }, }, - employeeincometax => { + employee_income_tax => { required => { message => 'no employee income tax sent.', status => 400 }, }, - employeegrosswage => { + employee_gross_wage => { required => { message => 'no employee gross wage sent.', status => 400 }, }, - employeeni => { + employee_ni => { required => { message => 'no employee ni sent.', status => 400 }, }, - employeepension => { + employee_pension => { required => { message => 'no employee pension sent.', status => 400 }, }, - employeeotherbenefit => { + employee_other_benefit => { required => { message => 'no employee other benefits sent.', status => 400 }, }, }; @@ -76,21 +76,21 @@ sub post_payroll { id => { "!=" => $user->id }, }); - $validation->required('entryperiod'); - $validation->required('employeeamount'); - $validation->required('localemployeeamount'); - $validation->required('grosspayroll'); - $validation->required('payrollincometax'); - $validation->required('payrollemployeeni'); - $validation->required('payrollemployerni'); - $validation->required('payrolltotalpension'); - $validation->required('payrollotherbenefit'); + $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; $c->schema->txn_do( sub { $user->entity->organisation->update({ - entry_period => $validation->param('entryperiod'), + entry_period => $validation->param('entry_period'), }); }); @@ -114,16 +114,16 @@ sub post_supplier { id => { "!=" => $user->id }, }); - $validation->required('entryperiod'); + $validation->required('entry_period'); $validation->required('postcode')->postcode; - $validation->required('supplierbusinessname'); - $validation->required('monthlyspend'); + $validation->required('supplier_business_name'); + $validation->required('monthly_spend'); return $c->api_validation_error if $validation->has_error; $c->schema->txn_do( sub { $user->entity->organisation->update({ - entry_period => $validation->param('entryperiod'), + entry_period => $validation->param('entry_period'), }); }); @@ -147,19 +147,19 @@ sub post_employee { id => { "!=" => $user->id }, }); - $validation->required('entryperiod'); - $validation->required('employeeno'); - $validation->required('employeeincometax'); - $validation->required('employeegrosswage'); - $validation->required('employeeni'); - $validation->required('employeepension'); - $validation->required('employeeotherbenefit'); + $validation->required('entry_period'); + $validation->required('employee_no'); + $validation->required('employee_income_tax'); + $validation->required('employee_gross_wage'); + $validation->required('employee_ni'); + $validation->required('employee_pension'); + $validation->required('employee_other_benefit'); return $c->api_validation_error if $validation->has_error; $c->schema->txn_do( sub { $user->entity->organisation->update({ - entry_period => $validation->param('entryperiod'), + entry_period => $validation->param('entry_period'), }); }); From 414acd76fb09ebd033b54a19cc5397dc2c3e1047 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 11:11:53 +0100 Subject: [PATCH 04/15] Transaction API errors improved --- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 25 ++++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index e7ae0d5..0a75f3f 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -54,13 +54,13 @@ has error_messages => sub { in => { message => 'transaction_type is not a valid value.', status => 400 }, }, transaction_value => { - required => { message => 'transaction_value is missing', status => 400 }, - number => { message => 'transaction_value does not look like a number', status => 400 }, - gt_num => { message => 'transaction_value cannot be equal to or less than zero', status => 400 }, + 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 }, + 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 }, @@ -68,15 +68,18 @@ has error_messages => sub { filetype => { message => 'File must be of type image/jpeg', status => 400 }, }, organisation_id => { - required => { message => '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 }, + 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 }, + required => { message => 'organisation name is missing', status => 400 }, + }, + town => { + required => { message => 'town/city is missing', status => 400 }, }, search_name => { - required => { message => 'search_name is missing', status => 400 }, + required => { message => 'search name is missing', status => 400 }, }, postcode => { required => { message => 'postcode is missing', status => 400 }, @@ -139,7 +142,7 @@ sub post_upload { # Unknown Organisation $validation->required('organisation_name'); $validation->optional('street_name'); - $validation->optional('town'); + $validation->required('town'); $validation->optional('postcode')->postcode; return $c->api_validation_error if $validation->has_error; From dd36cd0c0c68ffd4f13bb2cd954f73567a633164 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 11:31:57 +0100 Subject: [PATCH 05/15] Feedback API error improved --- lib/Pear/LocalLoop/Controller/Api/Feedback.pm | 2 +- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm index eafce88..f33eaec 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm @@ -5,7 +5,7 @@ has error_messages => sub { return { email => { required => { message => 'Email is required', status => 400 }, - in_resultset => { message => 'Change meeee', status => 400 }, + in_resultset => { message => 'Email does not exist in database', status => 400 }, }, feedbacktext => { required => { message => 'Feedback is required', status => 400 }, diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index 0a75f3f..f921d11 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -50,8 +50,8 @@ The postcode of an organisation, optional key. Used when transaction_Type is 3. 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 }, + 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 }, From 9e56383b4600b07c7b0edbfc47a51549889bc659 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 11:34:22 +0100 Subject: [PATCH 06/15] User and Register API errors improved --- lib/Pear/LocalLoop/Controller/Api/Register.pm | 20 +++++++++---------- lib/Pear/LocalLoop/Controller/Api/User.pm | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Register.pm b/lib/Pear/LocalLoop/Controller/Api/Register.pm index 8ba4f11..822087d 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Register.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Register.pm @@ -9,18 +9,18 @@ has error_messages => sub { in_resultset => { message => 'Token invalid or has been used.', status => 401 }, }, name => { - required => { message => 'No name sent or was blank.', status => 400 }, + required => { message => 'No organisation name sent or was blank.', status => 400 }, }, display_name => { - required => { message => 'No name sent or was blank.', status => 400 }, + required => { message => 'No display name sent or was blank.', status => 400 }, }, full_name => { - required => { message => 'No name sent or was blank.', status => 400 }, + 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 exists.', status => 403 }, + not_in_resultset => { message => 'Email already in use.', status => 403 }, }, postcode => { required => { message => 'No postcode sent.', status => 400 }, @@ -34,16 +34,16 @@ has error_messages => sub { 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 }, + 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 }, + required => { message => 'No street name sent.', status => 400 }, }, town => { - required => { message => 'No town sent.', status => 400 }, + required => { message => 'No town/city sent.', status => 400 }, }, }; }; diff --git a/lib/Pear/LocalLoop/Controller/Api/User.pm b/lib/Pear/LocalLoop/Controller/Api/User.pm index 0c0a2f3..d85e2d8 100644 --- a/lib/Pear/LocalLoop/Controller/Api/User.pm +++ b/lib/Pear/LocalLoop/Controller/Api/User.pm @@ -28,10 +28,10 @@ has error_messages => sub { required => { message => 'No password sent.', status => 400 }, }, street_name => { - required => { message => 'No street_name sent.', status => 400 }, + required => { message => 'No street name sent.', status => 400 }, }, town => { - required => { message => 'No town sent.', status => 400 }, + required => { message => 'No town/city sent.', status => 400 }, }, sector => { required => { message => 'No sector sent.', status => 400 }, From 5b3ef1bf2781f2c84b36f247e50f25436afe1e0c Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 12:05:30 +0100 Subject: [PATCH 07/15] Tests fixed --- t/api/register.t | 12 ++++++------ t/api/upload.t | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/t/api/register.t b/t/api/register.t index 203cde4..fd16642 100644 --- a/t/api/register.t +++ b/t/api/register.t @@ -73,7 +73,7 @@ $testJson = { $t->post_ok('/api/register' => json => $testJson) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/no name sent/i); + ->content_like(qr/no display name sent/i); #name missing JSON $testJson = { 'usertype' => 'customer', @@ -87,7 +87,7 @@ $testJson = { $t->post_ok('/api/register' => json => $testJson) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/no name sent/i); + ->content_like(qr/no full name sent/i); #Blank name $testJson = { @@ -235,7 +235,7 @@ $t->post_ok('/api/register' => json => $testJson) ->status_is(403) ->json_is('/success', Mojo::JSON->false) ->content_like(qr/email/i) - ->content_like(qr/exists/i); + ->content_like(qr/already in use/i); #postcode missing JSON $testJson = { @@ -315,7 +315,7 @@ $testJson = { $t->post_ok('/api/register' => json => $testJson) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/no year_of_birth sent/i); + ->content_like(qr/no year of birth sent/i); #Age is invalid $testJson = { @@ -331,7 +331,7 @@ $testJson = { $t->post_ok('/api/register' => json => $testJson) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/year_of_birth/i) + ->content_like(qr/year of birth/i) ->content_like(qr/invalid/i); #full address missing JSON @@ -347,7 +347,7 @@ $testJson = { $t->post_ok('/api/register' => json => $testJson) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/no street_name sent/i); + ->content_like(qr/no street name sent/i); #TODO Validation of full address diff --git a/t/api/upload.t b/t/api/upload.t index 74b3409..0522345 100644 --- a/t/api/upload.t +++ b/t/api/upload.t @@ -123,7 +123,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_value is missing/i); + ->content_like(qr/transaction amount is missing/i); print "test 7 - transaction_value non-numbers\n"; $json = { @@ -137,7 +137,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_value does not look like a number/i); + ->content_like(qr/transaction amount does not look like a number/i); print "test 8 - transaction_value equal to zero\n"; $json = { @@ -151,7 +151,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_value cannot be equal to or less than zero/i); + ->content_like(qr/transaction amount cannot be equal to or less than zero/i); print "test 9 - transaction_value less than zero\n"; $json = { @@ -165,7 +165,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_value cannot be equal to or less than zero/i); + ->content_like(qr/transaction amount cannot be equal to or less than zero/i); print "test 10 - transaction_type missing\n"; $json = { @@ -177,7 +177,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_type is missing/i); + ->content_like(qr/transaction type is missing/i); print "test 11 - transaction_type invalid.\n"; $json = { @@ -191,7 +191,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/transaction_type is not a valid value/i); + ->content_like(qr/transaction type is not a valid value/i); print "test 12 - file not uploaded.\n"; $json = { @@ -220,7 +220,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id is missing/i); + ->content_like(qr/organisation ID is missing/i); print "test 14 - organisation_id for non-existent id. (type 1: already validated)\n"; $json = { @@ -234,7 +234,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id does not exist in the database/i); + ->content_like(qr/organisation ID does not exist in the database/i); print "test 15 - valid addition. (type 1: already validated)\n"; is $schema->resultset('Transaction')->count, 1, "1 transaction"; @@ -268,7 +268,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_name is missing/i); + ->content_like(qr/organisation name is missing/i); print "test 17 - add valid transaction (type 3: new organisation)\n"; is $schema->resultset('Organisation')->search({ pending => 1 })->count, 0, "No pending organisations"; @@ -306,7 +306,7 @@ $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->or($framework->dump_error) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id is missing/i); + ->content_like(qr/organisation ID is missing/i); print "test 19 - organisation_id not a number (type 2: existing organisation)\n"; $json = { @@ -320,7 +320,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id is not a number/i); + ->content_like(qr/organisation ID is not a number/i); print "test 20 - id does not exist (type 2: existing organisation)\n"; $json = { @@ -334,7 +334,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id does not exist in the database/i); + ->content_like(qr/organisation ID does not exist in the database/i); print "test 21 - purchase_time is missing\n"; is $schema->resultset('Organisation')->search({ pending => 1 })->entity->sales->count, 1, "1 pending transactions"; @@ -385,7 +385,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->content_like(qr/organisation_id does not exist in the database/i); + ->content_like(qr/organisation ID does not exist in the database/i); is $schema->resultset('Organisation')->search({ pending => 1 })->entity->sales->count, 1, "1 pending transactions"; print "test 25 - Logout Hojo\n"; @@ -475,7 +475,7 @@ $upload = {json => Mojo::JSON::encode_json($json), file => {file => './t/test.jp $t->post_ok('/api/upload' => form => $upload ) ->status_is(400) ->json_is('/success', Mojo::JSON->false) - ->json_like('/message', qr/organisation_id does not exist in the database/); + ->json_like('/message', qr/organisation ID does not exist in the database/); is $schema->resultset('Transaction')->count, 6, "6 transaction"; done_testing(); From 9cb4f7c782e4897495b9ad71c7343a0201b06c4c Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 13:31:30 +0100 Subject: [PATCH 08/15] Added error rewrites and added feedback test --- lib/Pear/LocalLoop.pm | 2 +- lib/Pear/LocalLoop/Controller/Api/Feedback.pm | 4 +- t/api/feedback.t | 146 ++++++++++++++++++ 3 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 t/api/feedback.t diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index a1763b4..36e0c84 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -67,7 +67,7 @@ sub startup { json => { success => Mojo::JSON->false, message => $c->error_messages->{$val}->{$check}->{message}, - error => $check, + error => $c->error_messages->{$val}->{$check}->{error} || $check, }, status => $c->error_messages->{$val}->{$check}->{status}, ); diff --git a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm index f33eaec..cda98f1 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Feedback.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Feedback.pm @@ -4,8 +4,8 @@ use Mojo::Base 'Mojolicious::Controller'; has error_messages => sub { return { email => { - required => { message => 'Email is required', status => 400 }, - in_resultset => { message => 'Email does not exist in database', status => 400 }, + 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 }, diff --git a/t/api/feedback.t b/t/api/feedback.t new file mode 100644 index 0000000..6f8da2f --- /dev/null +++ b/t/api/feedback.t @@ -0,0 +1,146 @@ +use Mojo::Base -strict; + +use FindBin qw/ $Bin /; + +use Test::More; +use Mojo::JSON; +use Test::Pear::LocalLoop; + +my $framework = Test::Pear::LocalLoop->new( + etc_dir => "$Bin/../etc", +); +$framework->install_fixtures('users'); + +my $t = $framework->framework; +my $schema = $t->app->schema; + +#test email errors +$t->post_ok('/api/feedback' => json => { + email => '', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Email is required or not registered/); + +$t->post_ok('/api/feedback' => json => { + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Email is required or not registered/); + +$t->post_ok('/api/feedback' => json => { + email => 'banana', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Email is required or not registered/); + +$t->post_ok('/api/feedback' => json => { + email => 'test21318432148@example.com', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Email is required or not registered/); + +# Test for missing feedback +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Feedback is required/); + +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => '', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Feedback is required/); + +# Test for missing extra details +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => 'banana', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/App Name is required/); + +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Package Name is required/); + +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_number => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Version Code is required/); + +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + }) + ->status_is(400)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Version Number is required/); + +# Valid Feedback +$t->post_ok('/api/feedback' => json => { + email => 'test1@example.com', + feedbacktext => 'banana', + app_name => 'Foodloop Web', + package_name => 'Foodloop Web', + version_code => 'dev', + version_number => 'dev', + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->true); + +done_testing; From 616181def37e668a48aaf4367cd30a236c3a62a6 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 17:13:18 +0100 Subject: [PATCH 09/15] Payroll sumission API improved and test added --- doc/Fixtures/Users.md | 2 +- .../LocalLoop/Controller/Api/Organisation.pm | 45 ++-- .../LocalLoop/Schema/Result/Organisation.pm | 7 + .../Schema/Result/OrganisationPayroll.pm | 83 +++++++ t/api/organisation.t | 221 ++++++++++++++++++ 5 files changed, 342 insertions(+), 16 deletions(-) create mode 100644 lib/Pear/LocalLoop/Schema/Result/OrganisationPayroll.pm create mode 100644 t/api/organisation.t diff --git a/doc/Fixtures/Users.md b/doc/Fixtures/Users.md index 15db8d3..9545fe5 100644 --- a/doc/Fixtures/Users.md +++ b/doc/Fixtures/Users.md @@ -17,7 +17,7 @@ * email: test4@example.com * password: abc123 * Test Org - * email: test5@example.com + * email: org@example.com * password: abc123 * Test Admin * email: admin@example.com diff --git a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm index ce04ce4..effd9ee 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm @@ -17,47 +17,47 @@ has error_messages => sub { required => { message => 'No gross payroll sent.', status => 400 }, }, payroll_income_tax => { - required => { message => 'no payroll income tax sent.', status => 400 }, + required => { message => 'No total income tax sent.', status => 400 }, }, payroll_employee_ni => { - required => { message => 'no payroll employee ni sent.', status => 400 }, + required => { message => 'No total employee NI sent.', status => 400 }, }, payroll_employer_ni => { - required => { message => 'no payroll employer ni sent.', status => 400 }, + required => { message => 'No total employer NI sent.', status => 400 }, }, payroll_total_pension => { - required => { message => 'no payroll total pension sent.', status => 400 }, + required => { message => 'No total total pension sent.', status => 400 }, }, payroll_other_benefit => { - required => { message => 'no payroll other benefit sent.', status => 400 }, + required => { message => 'No total other benefits total sent.', status => 400 }, }, supplier_business_name => { - required => { message => 'no supplier business name sent.', status => 400 }, + required => { message => 'No supplier business name sent.', status => 400 }, }, postcode => { - required => { message => 'no postcode sent.', status => 400 }, + 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 }, + required => { message => 'No monthly spend sent.', status => 400 }, }, employee_no => { - required => { message => 'no employee no sent.', status => 400 }, + required => { message => 'No employee no sent.', status => 400 }, }, employee_income_tax => { - required => { message => 'no employee income tax sent.', status => 400 }, + required => { message => 'No employee income tax sent.', status => 400 }, }, employee_gross_wage => { - required => { message => 'no employee gross wage sent.', status => 400 }, + required => { message => 'No employee gross wage sent.', status => 400 }, }, employee_ni => { - required => { message => 'no employee ni sent.', status => 400 }, + required => { message => 'No employee ni sent.', status => 400 }, }, employee_pension => { - required => { message => 'no employee pension sent.', status => 400 }, + required => { message => 'No employee pension sent.', status => 400 }, }, employee_other_benefit => { - required => { message => 'no employee other benefits sent.', status => 400 }, + required => { message => 'No employee other benefits sent.', status => 400 }, }, }; }; @@ -86,11 +86,26 @@ sub post_payroll { $validation->required('payroll_total_pension'); $validation->required('payroll_other_benefit'); + 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'); + return $c->api_validation_error if $validation->has_error; $c->schema->txn_do( sub { - $user->entity->organisation->update({ + $user->entity->organisation->payroll->create({ entry_period => $validation->param('entry_period'), + employee_amount => $validation->param('employee_amount'), + local_employee_amount => $validation->param('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, }); }); diff --git a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm index 7f6c4c8..9512c18 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm @@ -68,6 +68,13 @@ __PACKAGE__->belongs_to( "entity_id", ); +__PACKAGE__->has_many( + "payroll", + "Pear::LocalLoop::Schema::Result::OrganisationPayroll", + { "foreign.org_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + __PACKAGE__->filter_column( pending => { filter_to_storage => 'to_bool', }); diff --git a/lib/Pear/LocalLoop/Schema/Result/OrganisationPayroll.pm b/lib/Pear/LocalLoop/Schema/Result/OrganisationPayroll.pm new file mode 100644 index 0000000..c60d458 --- /dev/null +++ b/lib/Pear/LocalLoop/Schema/Result/OrganisationPayroll.pm @@ -0,0 +1,83 @@ +package Pear::LocalLoop::Schema::Result::OrganisationPayroll; + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +__PACKAGE__->load_components(qw/ + InflateColumn::DateTime + TimeStamp +/); + +__PACKAGE__->table("organisation_payroll"); + +__PACKAGE__->add_columns( + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "org_id" => { + data_type => 'integer', + is_nullable => 0, + is_foreign_key => 1, + }, + "submitted_at" => { + data_type => "datetime", + is_nullable => 0, + set_on_create => 1, + }, + "entry_period" => { + data_type => "datetime", + is_nullable => 0, + }, + "employee_amount" => { + data_type => "integer", + is_nullable => 0, + }, + "local_employee_amount" => { + data_type => "integer", + is_nullable => 0, + }, + "gross_payroll" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "payroll_income_tax" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "payroll_employee_ni" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "payroll_employer_ni" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "payroll_total_pension" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, + "payroll_other_benefit" => { + data_type => "numeric", + size => [ 100, 0 ], + is_nullable => 0, + }, +); + +__PACKAGE__->set_primary_key("id"); + +__PACKAGE__->belongs_to( + "organisation", + "Pear::LocalLoop::Schema::Result::Organisation", + "org_id", +); + +1; diff --git a/t/api/organisation.t b/t/api/organisation.t new file mode 100644 index 0000000..7f05b87 --- /dev/null +++ b/t/api/organisation.t @@ -0,0 +1,221 @@ +use Mojo::Base -strict; + +use FindBin qw/ $Bin /; + +use Test::More; +use Mojo::JSON; +use Test::Pear::LocalLoop; +use DateTime; + +my $framework = Test::Pear::LocalLoop->new( + etc_dir => "$Bin/../etc", +); +$framework->install_fixtures('users'); + +my $t = $framework->framework; +my $schema = $t->app->schema; + +my $session_key = $framework->login({ + email => 'org@example.com', + password => 'abc123', +}); + +## Payroll Data Submission + +#No JSON sent +$t->post_ok('/api/org/payroll') + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/JSON is missing/i); + +#Empty JSON +$t->post_ok('/api/org/payroll' => json => {}) + ->json_is('/success', Mojo::JSON->false); + +# no session key +$t->post_ok('/api/org/payroll' => json => { + entry_period => '2017-12', + employee_amount => '10', + local_employee_amount => '10', + gross_payroll => '10', + payroll_income_tax => '10', + payroll_employee_ni => '10', + payroll_employer_ni => '10', + payroll_total_pension => '10', + payroll_other_benefit => '10', + }) + ->status_is(401) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/Invalid Session/); + +# No entry_period +$t->post_ok('/api/org/payroll' => json => { + session_key => $session_key, + employee_amount => '10', + local_employee_amount => '10', + gross_payroll => '10', + payroll_income_tax => '10', + payroll_employee_ni => '10', + payroll_employer_ni => '10', + payroll_total_pension => '10', + payroll_other_benefit => '10', + }) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/No entry period/); + +# No employee_amount +$t->post_ok('/api/org/payroll' => json => { + session_key => $session_key, + entry_period => '2017-12', + local_employee_amount => '10', + gross_payroll => '10', + payroll_income_tax => '10', + payroll_employee_ni => '10', + payroll_employer_ni => '10', + payroll_total_pension => '10', + payroll_other_benefit => '10', + }) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/No employee amount/); + +# No local_employee_amount +$t->post_ok('/api/org/payroll' => json => { + session_key => $session_key, + entry_period => '2017-12', + employee_amount => '10', + gross_payroll => '10', + payroll_income_tax => '10', + payroll_employee_ni => '10', + payroll_employer_ni => '10', + payroll_total_pension => '10', + payroll_other_benefit => '10', + }) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/local employee amount/); + +# No gross_payroll +$t->post_ok('/api/org/payroll' => json => { + session_key => $session_key, + entry_period => '2017-12', + employee_amount => '10', + local_employee_amount => '10', + payroll_income_tax => '10', + payroll_employee_ni => '10', + payroll_employer_ni => '10', + payroll_total_pension => '10', + payroll_other_benefit => '10', + }) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/No gross payroll/); + +# No payroll_income_tax +$t->post_ok('/api/org/payroll' => json => { + session_key => $session_key, + entry_period => '2017-12', + employee_amount => '10', + local_employee_amount => '10', + gross_payroll => '10', + payroll_employee_ni => '10', + payroll_employer_ni => '10', + payroll_total_pension => '10', + payroll_other_benefit => '10', + }) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/No total income tax/); + +# No payroll_employee_ni +$t->post_ok('/api/org/payroll' => json => { + session_key => $session_key, + entry_period => '2017-12', + employee_amount => '10', + local_employee_amount => '10', + gross_payroll => '10', + payroll_income_tax => '10', + payroll_employer_ni => '10', + payroll_total_pension => '10', + payroll_other_benefit => '10', + }) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/No total employee NI/); + +# No payroll_employer_ni +$t->post_ok('/api/org/payroll' => json => { + session_key => $session_key, + entry_period => '2017-12', + employee_amount => '10', + local_employee_amount => '10', + gross_payroll => '10', + payroll_income_tax => '10', + payroll_employee_ni => '10', + payroll_total_pension => '10', + payroll_other_benefit => '10', + }) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/total employer NI/); + +# No payroll_total_pension +$t->post_ok('/api/org/payroll' => json => { + session_key => $session_key, + entry_period => '2017-12', + employee_amount => '10', + local_employee_amount => '10', + gross_payroll => '10', + payroll_income_tax => '10', + payroll_employee_ni => '10', + payroll_employer_ni => '10', + payroll_other_benefit => '10', + }) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/No total total pension/); + +# No payroll_other_benefit +$t->post_ok('/api/org/payroll' => json => { + session_key => $session_key, + entry_period => '2017-12', + employee_amount => '10', + local_employee_amount => '10', + gross_payroll => '10', + payroll_income_tax => '10', + payroll_employee_ni => '10', + payroll_employer_ni => '10', + payroll_total_pension => '10', + }) + ->status_is(400) + ->json_is('/success', Mojo::JSON->false) + ->json_like('/message', qr/No total other benefits total/); + +# Valid payroll submission +$t->post_ok('/api/org/payroll' => json => { + session_key => $session_key, + entry_period => '2017-12', + employee_amount => '10', + local_employee_amount => '10', + gross_payroll => '10', + payroll_income_tax => '10', + payroll_employee_ni => '10', + payroll_employer_ni => '10', + payroll_total_pension => '10', + payroll_other_benefit => '10', + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->true); + +## Supplier Form submission + +#TODO make the test! + +## Employee Form submission + +#TODO make the test! + +$framework->logout( $session_key ); + +done_testing; From e388d360ac62ba81c736318061314fa152bb7d83 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 17:26:35 +0100 Subject: [PATCH 10/15] Changed endpoints in API --- lib/Pear/LocalLoop.pm | 6 ++--- .../LocalLoop/Controller/Api/Organisation.pm | 6 ++--- t/api/organisation.t | 26 +++++++++---------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 2130334..f41a504 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -144,9 +144,9 @@ sub startup { $api->post('/stats')->to('api-stats#post_index'); $api->post('/stats/leaderboard')->to('api-stats#post_leaderboards'); $api->post('/outgoing-transactions')->to('api-transactions#post_transaction_list_purchases'); - $api->post('/org/payroll')->to('api-organisation#post_payroll'); - $api->post('/org/supplier')->to('api-organisation#post_supplier'); - $api->post('/org/employee')->to('api-organisation#post_employee'); + $api->post('/org/payroll/add')->to('api-organisation#post_payroll_add'); + $api->post('/org/supplier/add')->to('api-organisation#post_supplier_add'); + $api->post('/org/employee/add')->to('api-organisation#post_employee_add'); my $api_v1 = $api->under('/v1'); diff --git a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm index effd9ee..7182a68 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm @@ -62,7 +62,7 @@ has error_messages => sub { }; }; -sub post_payroll { +sub post_payroll_add { my $c = shift; my $user = $c->stash->{api_user}; @@ -115,7 +115,7 @@ sub post_payroll { }); } -sub post_supplier { +sub post_supplier_add { my $c = shift; my $user = $c->stash->{api_user}; @@ -148,7 +148,7 @@ sub post_supplier { }); } -sub post_employee { +sub post_employee_add { my $c = shift; my $user = $c->stash->{api_user}; diff --git a/t/api/organisation.t b/t/api/organisation.t index 7f05b87..2331858 100644 --- a/t/api/organisation.t +++ b/t/api/organisation.t @@ -23,17 +23,17 @@ my $session_key = $framework->login({ ## Payroll Data Submission #No JSON sent -$t->post_ok('/api/org/payroll') +$t->post_ok('/api/org/payroll/add') ->status_is(400) ->json_is('/success', Mojo::JSON->false) ->json_like('/message', qr/JSON is missing/i); #Empty JSON -$t->post_ok('/api/org/payroll' => json => {}) +$t->post_ok('/api/org/payroll/add' => json => {}) ->json_is('/success', Mojo::JSON->false); # no session key -$t->post_ok('/api/org/payroll' => json => { +$t->post_ok('/api/org/payroll/add' => json => { entry_period => '2017-12', employee_amount => '10', local_employee_amount => '10', @@ -49,7 +49,7 @@ $t->post_ok('/api/org/payroll' => json => { ->json_like('/message', qr/Invalid Session/); # No entry_period -$t->post_ok('/api/org/payroll' => json => { +$t->post_ok('/api/org/payroll/add' => json => { session_key => $session_key, employee_amount => '10', local_employee_amount => '10', @@ -65,7 +65,7 @@ $t->post_ok('/api/org/payroll' => json => { ->json_like('/message', qr/No entry period/); # No employee_amount -$t->post_ok('/api/org/payroll' => json => { +$t->post_ok('/api/org/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', local_employee_amount => '10', @@ -81,7 +81,7 @@ $t->post_ok('/api/org/payroll' => json => { ->json_like('/message', qr/No employee amount/); # No local_employee_amount -$t->post_ok('/api/org/payroll' => json => { +$t->post_ok('/api/org/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -97,7 +97,7 @@ $t->post_ok('/api/org/payroll' => json => { ->json_like('/message', qr/local employee amount/); # No gross_payroll -$t->post_ok('/api/org/payroll' => json => { +$t->post_ok('/api/org/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -113,7 +113,7 @@ $t->post_ok('/api/org/payroll' => json => { ->json_like('/message', qr/No gross payroll/); # No payroll_income_tax -$t->post_ok('/api/org/payroll' => json => { +$t->post_ok('/api/org/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -129,7 +129,7 @@ $t->post_ok('/api/org/payroll' => json => { ->json_like('/message', qr/No total income tax/); # No payroll_employee_ni -$t->post_ok('/api/org/payroll' => json => { +$t->post_ok('/api/org/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -145,7 +145,7 @@ $t->post_ok('/api/org/payroll' => json => { ->json_like('/message', qr/No total employee NI/); # No payroll_employer_ni -$t->post_ok('/api/org/payroll' => json => { +$t->post_ok('/api/org/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -161,7 +161,7 @@ $t->post_ok('/api/org/payroll' => json => { ->json_like('/message', qr/total employer NI/); # No payroll_total_pension -$t->post_ok('/api/org/payroll' => json => { +$t->post_ok('/api/org/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -177,7 +177,7 @@ $t->post_ok('/api/org/payroll' => json => { ->json_like('/message', qr/No total total pension/); # No payroll_other_benefit -$t->post_ok('/api/org/payroll' => json => { +$t->post_ok('/api/org/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -193,7 +193,7 @@ $t->post_ok('/api/org/payroll' => json => { ->json_like('/message', qr/No total other benefits total/); # Valid payroll submission -$t->post_ok('/api/org/payroll' => json => { +$t->post_ok('/api/org/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', From 78964d729759b796efbad372b3fbad378688240d Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 18 Sep 2017 17:31:29 +0100 Subject: [PATCH 11/15] Made endpoints org only --- lib/Pear/LocalLoop.pm | 7 ++++--- t/api/organisation.t | 26 +++++++++++++------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index f41a504..dcd312b 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -144,9 +144,7 @@ sub startup { $api->post('/stats')->to('api-stats#post_index'); $api->post('/stats/leaderboard')->to('api-stats#post_leaderboards'); $api->post('/outgoing-transactions')->to('api-transactions#post_transaction_list_purchases'); - $api->post('/org/payroll/add')->to('api-organisation#post_payroll_add'); - $api->post('/org/supplier/add')->to('api-organisation#post_supplier_add'); - $api->post('/org/employee/add')->to('api-organisation#post_employee_add'); + my $api_v1 = $api->under('/v1'); @@ -154,6 +152,9 @@ sub startup { $api_v1_org->post('/graphs')->to('api-v1-organisation-graphs#index'); $api_v1_org->post('/snippets')->to('api-v1-organisation-snippets#index'); + $api_v1_org->post('/payroll/add')->to('api-organisation#post_payroll_add'); + $api_v1_org->post('/supplier/add')->to('api-organisation#post_supplier_add'); + $api_v1_org->post('/employee/add')->to('api-organisation#post_employee_add'); my $admin_routes = $r->under('/admin')->to('admin#under'); diff --git a/t/api/organisation.t b/t/api/organisation.t index 2331858..2ae3fa3 100644 --- a/t/api/organisation.t +++ b/t/api/organisation.t @@ -23,17 +23,17 @@ my $session_key = $framework->login({ ## Payroll Data Submission #No JSON sent -$t->post_ok('/api/org/payroll/add') +$t->post_ok('/api/v1/organisation/payroll/add') ->status_is(400) ->json_is('/success', Mojo::JSON->false) ->json_like('/message', qr/JSON is missing/i); #Empty JSON -$t->post_ok('/api/org/payroll/add' => json => {}) +$t->post_ok('/api/v1/organisation/payroll/add' => json => {}) ->json_is('/success', Mojo::JSON->false); # no session key -$t->post_ok('/api/org/payroll/add' => json => { +$t->post_ok('/api/v1/organisation/payroll/add' => json => { entry_period => '2017-12', employee_amount => '10', local_employee_amount => '10', @@ -49,7 +49,7 @@ $t->post_ok('/api/org/payroll/add' => json => { ->json_like('/message', qr/Invalid Session/); # No entry_period -$t->post_ok('/api/org/payroll/add' => json => { +$t->post_ok('/api/v1/organisation/payroll/add' => json => { session_key => $session_key, employee_amount => '10', local_employee_amount => '10', @@ -65,7 +65,7 @@ $t->post_ok('/api/org/payroll/add' => json => { ->json_like('/message', qr/No entry period/); # No employee_amount -$t->post_ok('/api/org/payroll/add' => json => { +$t->post_ok('/api/v1/organisation/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', local_employee_amount => '10', @@ -81,7 +81,7 @@ $t->post_ok('/api/org/payroll/add' => json => { ->json_like('/message', qr/No employee amount/); # No local_employee_amount -$t->post_ok('/api/org/payroll/add' => json => { +$t->post_ok('/api/v1/organisation/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -97,7 +97,7 @@ $t->post_ok('/api/org/payroll/add' => json => { ->json_like('/message', qr/local employee amount/); # No gross_payroll -$t->post_ok('/api/org/payroll/add' => json => { +$t->post_ok('/api/v1/organisation/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -113,7 +113,7 @@ $t->post_ok('/api/org/payroll/add' => json => { ->json_like('/message', qr/No gross payroll/); # No payroll_income_tax -$t->post_ok('/api/org/payroll/add' => json => { +$t->post_ok('/api/v1/organisation/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -129,7 +129,7 @@ $t->post_ok('/api/org/payroll/add' => json => { ->json_like('/message', qr/No total income tax/); # No payroll_employee_ni -$t->post_ok('/api/org/payroll/add' => json => { +$t->post_ok('/api/v1/organisation/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -145,7 +145,7 @@ $t->post_ok('/api/org/payroll/add' => json => { ->json_like('/message', qr/No total employee NI/); # No payroll_employer_ni -$t->post_ok('/api/org/payroll/add' => json => { +$t->post_ok('/api/v1/organisation/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -161,7 +161,7 @@ $t->post_ok('/api/org/payroll/add' => json => { ->json_like('/message', qr/total employer NI/); # No payroll_total_pension -$t->post_ok('/api/org/payroll/add' => json => { +$t->post_ok('/api/v1/organisation/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -177,7 +177,7 @@ $t->post_ok('/api/org/payroll/add' => json => { ->json_like('/message', qr/No total total pension/); # No payroll_other_benefit -$t->post_ok('/api/org/payroll/add' => json => { +$t->post_ok('/api/v1/organisation/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', @@ -193,7 +193,7 @@ $t->post_ok('/api/org/payroll/add' => json => { ->json_like('/message', qr/No total other benefits total/); # Valid payroll submission -$t->post_ok('/api/org/payroll/add' => json => { +$t->post_ok('/api/v1/organisation/payroll/add' => json => { session_key => $session_key, entry_period => '2017-12', employee_amount => '10', From 813f4af63f143f603df398913fa64a696c9f5958 Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 19 Sep 2017 14:41:11 +0100 Subject: [PATCH 12/15] New routes added --- lib/Pear/LocalLoop.pm | 3 +++ lib/Pear/LocalLoop/Controller/Api/Organisation.pm | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index dcd312b..044b322 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -152,8 +152,11 @@ sub startup { $api_v1_org->post('/graphs')->to('api-v1-organisation-graphs#index'); $api_v1_org->post('/snippets')->to('api-v1-organisation-snippets#index'); + $api_v1_org->post('/payroll')->to('api-organisation#post_payroll_read'); $api_v1_org->post('/payroll/add')->to('api-organisation#post_payroll_add'); + $api_v1_org->post('/supplier')->to('api-organisation#post_supplier_read'); $api_v1_org->post('/supplier/add')->to('api-organisation#post_supplier_add'); + $api_v1_org->post('/employee')->to('api-organisation#post_employee_read'); $api_v1_org->post('/employee/add')->to('api-organisation#post_employee_add'); my $admin_routes = $r->under('/admin')->to('admin#under'); diff --git a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm index 7182a68..4d88e9f 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm @@ -62,6 +62,10 @@ has error_messages => sub { }; }; +sub post_payroll_read { + +} + sub post_payroll_add { my $c = shift; @@ -115,6 +119,10 @@ sub post_payroll_add { }); } +sub post_supplier_read { + +} + sub post_supplier_add { my $c = shift; @@ -148,6 +156,10 @@ sub post_supplier_add { }); } +sub post_employee_read { + +} + sub post_employee_add { my $c = shift; From 8e2cecfcf5671c39c349cfa439e78dd16d51adfe Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 19 Sep 2017 15:50:58 +0100 Subject: [PATCH 13/15] added read API --- .../LocalLoop/Controller/Api/Organisation.pm | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm index 4d88e9f..1a81aee 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm @@ -63,7 +63,44 @@ has error_messages => sub { }; sub post_payroll_read { + my $c = shift; + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->optional('page')->number; + + return $c->api_validation_error if $validation->has_error; + + my $payrolls = $user->entity->organisation->payroll->search( + undef, { + page => $validation->param('page') || 1, + rows => 10, + order_by => { -desc => 'submitted_at' }, + }, + ); + +# purchase_time needs timezone attached to it + my @payroll_list = ( + map {{ + entry_period => $_->entry_period, + employee_amount => $_->employee_amount, + local_employee_amount => $_->local_employee_amount, + gross_payroll => $_->gross_payroll / 100000, + payroll_income_tax => $_->payroll_income_tax / 100000, + payroll_employee_ni => $_->payroll_employee_ni / 100000, + payroll_employer_ni => $_->payroll_employer_ni / 100000, + payroll_total_pension => $_->payroll_total_pension / 100000, + payroll_other_benefit => $_->payroll_other_benefit / 100000, + }} $payrolls->all + ); + + return $c->render( json => { + success => Mojo::JSON->true, + transactions => \@payroll_list, + page_no => $payrolls->pager->total_entries, + }); } sub post_payroll_add { @@ -101,15 +138,15 @@ sub post_payroll_add { $c->schema->txn_do( sub { $user->entity->organisation->payroll->create({ - entry_period => $validation->param('entry_period'), - employee_amount => $validation->param('employee_amount'), - local_employee_amount => $validation->param('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, + entry_period => $validation->param('entry_period'), + employee_amount => $validation->param('employee_amount'), + local_employee_amount => $validation->param('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, }); }); From 5f241bbd46e35eebb05e6f6ee2a224f3cd5022ad Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 19 Sep 2017 17:23:30 +0100 Subject: [PATCH 14/15] Tests fixed and API improved and DB upgraded --- .../LocalLoop/Controller/Api/Organisation.pm | 15 +- lib/Pear/LocalLoop/Plugin/Datetime.pm | 18 + lib/Pear/LocalLoop/Schema.pm | 2 +- .../deploy/8/001-auto-__VERSION.sql | 18 + share/ddl/PostgreSQL/deploy/8/001-auto.sql | 235 ++++ share/ddl/PostgreSQL/upgrade/7-8/001-auto.sql | 31 + .../SQLite/deploy/8/001-auto-__VERSION.sql | 18 + share/ddl/SQLite/deploy/8/001-auto.sql | 164 +++ share/ddl/SQLite/upgrade/7-8/001-auto.sql | 29 + .../_source/deploy/8/001-auto-__VERSION.yml | 91 ++ share/ddl/_source/deploy/8/001-auto.yml | 1229 +++++++++++++++++ t/api/organisation.t | 18 + 12 files changed, 1861 insertions(+), 7 deletions(-) create mode 100644 share/ddl/PostgreSQL/deploy/8/001-auto-__VERSION.sql create mode 100644 share/ddl/PostgreSQL/deploy/8/001-auto.sql create mode 100644 share/ddl/PostgreSQL/upgrade/7-8/001-auto.sql create mode 100644 share/ddl/SQLite/deploy/8/001-auto-__VERSION.sql create mode 100644 share/ddl/SQLite/deploy/8/001-auto.sql create mode 100644 share/ddl/SQLite/upgrade/7-8/001-auto.sql create mode 100644 share/ddl/_source/deploy/8/001-auto-__VERSION.yml create mode 100644 share/ddl/_source/deploy/8/001-auto.yml diff --git a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm index 1a81aee..aaabb8a 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Organisation.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Organisation.pm @@ -98,7 +98,7 @@ sub post_payroll_read { return $c->render( json => { success => Mojo::JSON->true, - transactions => \@payroll_list, + payrolls => \@payroll_list, page_no => $payrolls->pager->total_entries, }); } @@ -127,6 +127,11 @@ sub post_payroll_add { $validation->required('payroll_total_pension'); $validation->required('payroll_other_benefit'); + return $c->api_validation_error if $validation->has_error; + + my $entry_period = $c->parse_iso_month($validation->param('entry_period')); + my $employee_amount = $validation->param('employee_amount'); + my $local_employee_amount = $validation->param('local_employee_amount'); my $gross_payroll = $validation->param('gross_payroll'); my $payroll_income_tax = $validation->param('payroll_income_tax'); my $payroll_employee_ni = $validation->param('payroll_employee_ni'); @@ -134,13 +139,11 @@ sub post_payroll_add { my $payroll_total_pension = $validation->param('payroll_total_pension'); my $payroll_other_benefit = $validation->param('payroll_other_benefit'); - return $c->api_validation_error if $validation->has_error; - $c->schema->txn_do( sub { $user->entity->organisation->payroll->create({ - entry_period => $validation->param('entry_period'), - employee_amount => $validation->param('employee_amount'), - local_employee_amount => $validation->param('local_employee_amount'), + 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, diff --git a/lib/Pear/LocalLoop/Plugin/Datetime.pm b/lib/Pear/LocalLoop/Plugin/Datetime.pm index 8b7495a..c598709 100644 --- a/lib/Pear/LocalLoop/Plugin/Datetime.pm +++ b/lib/Pear/LocalLoop/Plugin/Datetime.pm @@ -14,6 +14,10 @@ sub register { return DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' ); }); + $app->helper( iso_month_parser => sub { + return DateTime::Format::Strptime->new( pattern => '%Y-%m' ); + }); + $app->helper( parse_iso_date => sub { my ( $c, $date_string ) = @_; return $c->iso_date_parser->parse_datetime( @@ -28,6 +32,20 @@ sub register { ); }); + $app->helper( parse_iso_month => sub { + my ( $c, $date_string ) = @_; + return $c->iso_month_parser->parse_datetime( + $date_string, + ); + }); + + $app->helper( format_iso_month => sub { + my ( $c, $datetime_obj ) = @_; + return $c->iso_month_parser->format_datetime( + $datetime_obj, + ); + }); + $app->helper( parse_iso_datetime => sub { my ( $c, $date_string ) = @_; return $c->iso_datetime_parser->parse_datetime( diff --git a/lib/Pear/LocalLoop/Schema.pm b/lib/Pear/LocalLoop/Schema.pm index a7fc365..89e7b3b 100644 --- a/lib/Pear/LocalLoop/Schema.pm +++ b/lib/Pear/LocalLoop/Schema.pm @@ -6,7 +6,7 @@ use warnings; use base 'DBIx::Class::Schema'; -our $VERSION = 7; +our $VERSION = 8; __PACKAGE__->load_namespaces; diff --git a/share/ddl/PostgreSQL/deploy/8/001-auto-__VERSION.sql b/share/ddl/PostgreSQL/deploy/8/001-auto-__VERSION.sql new file mode 100644 index 0000000..98c75c4 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/8/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Tue Sep 19 16:52:01 2017 +-- +; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE "dbix_class_deploymenthandler_versions" ( + "id" serial NOT NULL, + "version" character varying(50) NOT NULL, + "ddl" text, + "upgrade_sql" text, + PRIMARY KEY ("id"), + CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version") +); + +; diff --git a/share/ddl/PostgreSQL/deploy/8/001-auto.sql b/share/ddl/PostgreSQL/deploy/8/001-auto.sql new file mode 100644 index 0000000..2d33176 --- /dev/null +++ b/share/ddl/PostgreSQL/deploy/8/001-auto.sql @@ -0,0 +1,235 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Tue Sep 19 16:52:01 2017 +-- +; +-- +-- Table: account_tokens +-- +CREATE TABLE "account_tokens" ( + "id" serial NOT NULL, + "name" text NOT NULL, + "used" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "account_tokens_name" UNIQUE ("name") +); + +; +-- +-- Table: entities +-- +CREATE TABLE "entities" ( + "id" serial NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); + +; +-- +-- Table: leaderboards +-- +CREATE TABLE "leaderboards" ( + "id" serial NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboards_type" UNIQUE ("type") +); + +; +-- +-- Table: customers +-- +CREATE TABLE "customers" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "display_name" character varying(255) NOT NULL, + "full_name" character varying(255) NOT NULL, + "year_of_birth" integer NOT NULL, + "postcode" character varying(16) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "customers_idx_entity_id" on "customers" ("entity_id"); + +; +-- +-- Table: leaderboard_sets +-- +CREATE TABLE "leaderboard_sets" ( + "id" serial NOT NULL, + "leaderboard_id" integer NOT NULL, + "date" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "leaderboard_sets_idx_leaderboard_id" on "leaderboard_sets" ("leaderboard_id"); + +; +-- +-- Table: organisations +-- +CREATE TABLE "organisations" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "street_name" text, + "town" character varying(255) NOT NULL, + "postcode" character varying(16), + "country" character varying(255), + "sector" character varying(1), + "pending" boolean DEFAULT false NOT NULL, + "submitted_by_id" integer, + PRIMARY KEY ("id") +); +CREATE INDEX "organisations_idx_entity_id" on "organisations" ("entity_id"); + +; +-- +-- Table: transactions +-- +CREATE TABLE "transactions" ( + "id" serial NOT NULL, + "buyer_id" integer NOT NULL, + "seller_id" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "proof_image" text, + "submitted_at" timestamp NOT NULL, + "purchase_time" timestamp NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "transactions_idx_buyer_id" on "transactions" ("buyer_id"); +CREATE INDEX "transactions_idx_seller_id" on "transactions" ("seller_id"); + +; +-- +-- Table: users +-- +CREATE TABLE "users" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "email" text NOT NULL, + "join_date" timestamp NOT NULL, + "password" character varying(100) NOT NULL, + "is_admin" boolean DEFAULT false NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "users_email" UNIQUE ("email") +); +CREATE INDEX "users_idx_entity_id" on "users" ("entity_id"); + +; +-- +-- Table: feedback +-- +CREATE TABLE "feedback" ( + "id" serial NOT NULL, + "user_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "feedbacktext" text NOT NULL, + "app_name" character varying(255) NOT NULL, + "package_name" character varying(255) NOT NULL, + "version_code" character varying(255) NOT NULL, + "version_number" character varying(255) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "feedback_idx_user_id" on "feedback" ("user_id"); + +; +-- +-- Table: organisation_payroll +-- +CREATE TABLE "organisation_payroll" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "entry_period" timestamp NOT NULL, + "employee_amount" integer NOT NULL, + "local_employee_amount" integer NOT NULL, + "gross_payroll" numeric(100,0) NOT NULL, + "payroll_income_tax" numeric(100,0) NOT NULL, + "payroll_employee_ni" numeric(100,0) NOT NULL, + "payroll_employer_ni" numeric(100,0) NOT NULL, + "payroll_total_pension" numeric(100,0) NOT NULL, + "payroll_other_benefit" numeric(100,0) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisation_payroll_idx_org_id" on "organisation_payroll" ("org_id"); + +; +-- +-- Table: session_tokens +-- +CREATE TABLE "session_tokens" ( + "id" serial NOT NULL, + "token" character varying(255) NOT NULL, + "user_id" integer NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "session_tokens_token" UNIQUE ("token") +); +CREATE INDEX "session_tokens_idx_user_id" on "session_tokens" ("user_id"); + +; +-- +-- Table: leaderboard_values +-- +CREATE TABLE "leaderboard_values" ( + "id" serial NOT NULL, + "entity_id" integer NOT NULL, + "set_id" integer NOT NULL, + "position" integer NOT NULL, + "value" numeric(100,0) NOT NULL, + "trend" integer DEFAULT 0 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "leaderboard_values_entity_id_set_id" UNIQUE ("entity_id", "set_id") +); +CREATE INDEX "leaderboard_values_idx_entity_id" on "leaderboard_values" ("entity_id"); +CREATE INDEX "leaderboard_values_idx_set_id" on "leaderboard_values" ("set_id"); + +; +-- +-- Foreign Key Definitions +-- + +; +ALTER TABLE "customers" ADD CONSTRAINT "customers_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "leaderboard_sets" ADD CONSTRAINT "leaderboard_sets_fk_leaderboard_id" FOREIGN KEY ("leaderboard_id") + REFERENCES "leaderboards" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisations" ADD CONSTRAINT "organisations_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_buyer_id" FOREIGN KEY ("buyer_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "transactions" ADD CONSTRAINT "transactions_fk_seller_id" FOREIGN KEY ("seller_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "users" ADD CONSTRAINT "users_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE CASCADE DEFERRABLE; + +; +ALTER TABLE "feedback" ADD CONSTRAINT "feedback_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "organisation_payroll" ADD CONSTRAINT "organisation_payroll_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") DEFERRABLE; + +; +ALTER TABLE "session_tokens" ADD CONSTRAINT "session_tokens_fk_user_id" FOREIGN KEY ("user_id") + REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_entity_id" FOREIGN KEY ("entity_id") + REFERENCES "entities" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; +ALTER TABLE "leaderboard_values" ADD CONSTRAINT "leaderboard_values_fk_set_id" FOREIGN KEY ("set_id") + REFERENCES "leaderboard_sets" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +; diff --git a/share/ddl/PostgreSQL/upgrade/7-8/001-auto.sql b/share/ddl/PostgreSQL/upgrade/7-8/001-auto.sql new file mode 100644 index 0000000..c455c23 --- /dev/null +++ b/share/ddl/PostgreSQL/upgrade/7-8/001-auto.sql @@ -0,0 +1,31 @@ +-- Convert schema 'share/ddl/_source/deploy/7/001-auto.yml' to 'share/ddl/_source/deploy/8/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE "organisation_payroll" ( + "id" serial NOT NULL, + "org_id" integer NOT NULL, + "submitted_at" timestamp NOT NULL, + "entry_period" timestamp NOT NULL, + "employee_amount" integer NOT NULL, + "local_employee_amount" integer NOT NULL, + "gross_payroll" numeric(100,0) NOT NULL, + "payroll_income_tax" numeric(100,0) NOT NULL, + "payroll_employee_ni" numeric(100,0) NOT NULL, + "payroll_employer_ni" numeric(100,0) NOT NULL, + "payroll_total_pension" numeric(100,0) NOT NULL, + "payroll_other_benefit" numeric(100,0) NOT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "organisation_payroll_idx_org_id" on "organisation_payroll" ("org_id"); + +; +ALTER TABLE "organisation_payroll" ADD CONSTRAINT "organisation_payroll_fk_org_id" FOREIGN KEY ("org_id") + REFERENCES "organisations" ("id") DEFERRABLE; + +; + +COMMIT; + diff --git a/share/ddl/SQLite/deploy/8/001-auto-__VERSION.sql b/share/ddl/SQLite/deploy/8/001-auto-__VERSION.sql new file mode 100644 index 0000000..2085dfd --- /dev/null +++ b/share/ddl/SQLite/deploy/8/001-auto-__VERSION.sql @@ -0,0 +1,18 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Tue Sep 19 16:52:01 2017 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: dbix_class_deploymenthandler_versions +-- +CREATE TABLE dbix_class_deploymenthandler_versions ( + id INTEGER PRIMARY KEY NOT NULL, + version varchar(50) NOT NULL, + ddl text, + upgrade_sql text +); +CREATE UNIQUE INDEX dbix_class_deploymenthandler_versions_version ON dbix_class_deploymenthandler_versions (version); +COMMIT; diff --git a/share/ddl/SQLite/deploy/8/001-auto.sql b/share/ddl/SQLite/deploy/8/001-auto.sql new file mode 100644 index 0000000..0894367 --- /dev/null +++ b/share/ddl/SQLite/deploy/8/001-auto.sql @@ -0,0 +1,164 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Tue Sep 19 16:52:01 2017 +-- + +; +BEGIN TRANSACTION; +-- +-- Table: account_tokens +-- +CREATE TABLE account_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + name text NOT NULL, + used integer NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX account_tokens_name ON account_tokens (name); +-- +-- Table: entities +-- +CREATE TABLE entities ( + id INTEGER PRIMARY KEY NOT NULL, + type varchar(255) NOT NULL +); +-- +-- Table: leaderboards +-- +CREATE TABLE leaderboards ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + type varchar(255) NOT NULL +); +CREATE UNIQUE INDEX leaderboards_type ON leaderboards (type); +-- +-- Table: customers +-- +CREATE TABLE customers ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + display_name varchar(255) NOT NULL, + full_name varchar(255) NOT NULL, + year_of_birth integer NOT NULL, + postcode varchar(16) NOT NULL, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX customers_idx_entity_id ON customers (entity_id); +-- +-- Table: leaderboard_sets +-- +CREATE TABLE leaderboard_sets ( + id INTEGER PRIMARY KEY NOT NULL, + leaderboard_id integer NOT NULL, + date datetime NOT NULL, + FOREIGN KEY (leaderboard_id) REFERENCES leaderboards(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_sets_idx_leaderboard_id ON leaderboard_sets (leaderboard_id); +-- +-- Table: organisations +-- +CREATE TABLE organisations ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + name varchar(255) NOT NULL, + street_name text, + town varchar(255) NOT NULL, + postcode varchar(16), + country varchar(255), + sector varchar(1), + pending boolean NOT NULL DEFAULT false, + submitted_by_id integer, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX organisations_idx_entity_id ON organisations (entity_id); +-- +-- Table: transactions +-- +CREATE TABLE transactions ( + id INTEGER PRIMARY KEY NOT NULL, + buyer_id integer NOT NULL, + seller_id integer NOT NULL, + value numeric(100,0) NOT NULL, + proof_image text, + submitted_at datetime NOT NULL, + purchase_time datetime NOT NULL, + FOREIGN KEY (buyer_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (seller_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX transactions_idx_buyer_id ON transactions (buyer_id); +CREATE INDEX transactions_idx_seller_id ON transactions (seller_id); +-- +-- Table: users +-- +CREATE TABLE users ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + email text NOT NULL, + join_date datetime NOT NULL, + password varchar(100) NOT NULL, + is_admin boolean NOT NULL DEFAULT false, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE +); +CREATE INDEX users_idx_entity_id ON users (entity_id); +CREATE UNIQUE INDEX users_email ON users (email); +-- +-- Table: feedback +-- +CREATE TABLE feedback ( + id INTEGER PRIMARY KEY NOT NULL, + user_id integer NOT NULL, + submitted_at datetime NOT NULL, + feedbacktext text NOT NULL, + app_name varchar(255) NOT NULL, + package_name varchar(255) NOT NULL, + version_code varchar(255) NOT NULL, + version_number varchar(255) NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX feedback_idx_user_id ON feedback (user_id); +-- +-- Table: organisation_payroll +-- +CREATE TABLE organisation_payroll ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + submitted_at datetime NOT NULL, + entry_period datetime NOT NULL, + employee_amount integer NOT NULL, + local_employee_amount integer NOT NULL, + gross_payroll numeric(100,0) NOT NULL, + payroll_income_tax numeric(100,0) NOT NULL, + payroll_employee_ni numeric(100,0) NOT NULL, + payroll_employer_ni numeric(100,0) NOT NULL, + payroll_total_pension numeric(100,0) NOT NULL, + payroll_other_benefit numeric(100,0) NOT NULL, + FOREIGN KEY (org_id) REFERENCES organisations(id) +); +CREATE INDEX organisation_payroll_idx_org_id ON organisation_payroll (org_id); +-- +-- Table: session_tokens +-- +CREATE TABLE session_tokens ( + id INTEGER PRIMARY KEY NOT NULL, + token varchar(255) NOT NULL, + user_id integer NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX session_tokens_idx_user_id ON session_tokens (user_id); +CREATE UNIQUE INDEX session_tokens_token ON session_tokens (token); +-- +-- Table: leaderboard_values +-- +CREATE TABLE leaderboard_values ( + id INTEGER PRIMARY KEY NOT NULL, + entity_id integer NOT NULL, + set_id integer NOT NULL, + position integer NOT NULL, + value numeric(100,0) NOT NULL, + trend integer NOT NULL DEFAULT 0, + FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE NO ACTION ON UPDATE NO ACTION, + FOREIGN KEY (set_id) REFERENCES leaderboard_sets(id) ON DELETE NO ACTION ON UPDATE NO ACTION +); +CREATE INDEX leaderboard_values_idx_entity_id ON leaderboard_values (entity_id); +CREATE INDEX leaderboard_values_idx_set_id ON leaderboard_values (set_id); +CREATE UNIQUE INDEX leaderboard_values_entity_id_set_id ON leaderboard_values (entity_id, set_id); +COMMIT; diff --git a/share/ddl/SQLite/upgrade/7-8/001-auto.sql b/share/ddl/SQLite/upgrade/7-8/001-auto.sql new file mode 100644 index 0000000..5355259 --- /dev/null +++ b/share/ddl/SQLite/upgrade/7-8/001-auto.sql @@ -0,0 +1,29 @@ +-- Convert schema 'share/ddl/_source/deploy/7/001-auto.yml' to 'share/ddl/_source/deploy/8/001-auto.yml':; + +; +BEGIN; + +; +CREATE TABLE organisation_payroll ( + id INTEGER PRIMARY KEY NOT NULL, + org_id integer NOT NULL, + submitted_at datetime NOT NULL, + entry_period datetime NOT NULL, + employee_amount integer NOT NULL, + local_employee_amount integer NOT NULL, + gross_payroll numeric(100,0) NOT NULL, + payroll_income_tax numeric(100,0) NOT NULL, + payroll_employee_ni numeric(100,0) NOT NULL, + payroll_employer_ni numeric(100,0) NOT NULL, + payroll_total_pension numeric(100,0) NOT NULL, + payroll_other_benefit numeric(100,0) NOT NULL, + FOREIGN KEY (org_id) REFERENCES organisations(id) +); + +; +CREATE INDEX organisation_payroll_idx_org_id ON organisation_payroll (org_id); + +; + +COMMIT; + diff --git a/share/ddl/_source/deploy/8/001-auto-__VERSION.yml b/share/ddl/_source/deploy/8/001-auto-__VERSION.yml new file mode 100644 index 0000000..907f443 --- /dev/null +++ b/share/ddl/_source/deploy/8/001-auto-__VERSION.yml @@ -0,0 +1,91 @@ +--- +schema: + procedures: {} + tables: + dbix_class_deploymenthandler_versions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - version + match_type: '' + name: dbix_class_deploymenthandler_versions_version + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + ddl: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: ddl + order: 3 + size: + - 0 + id: + data_type: int + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + upgrade_sql: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: upgrade_sql + order: 4 + size: + - 0 + version: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: version + order: 2 + size: + - 50 + indices: [] + name: dbix_class_deploymenthandler_versions + options: [] + order: 1 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - __VERSION + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 diff --git a/share/ddl/_source/deploy/8/001-auto.yml b/share/ddl/_source/deploy/8/001-auto.yml new file mode 100644 index 0000000..a47e6aa --- /dev/null +++ b/share/ddl/_source/deploy/8/001-auto.yml @@ -0,0 +1,1229 @@ +--- +schema: + procedures: {} + tables: + account_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: account_tokens_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 2 + size: + - 0 + used: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: used + order: 3 + size: + - 0 + indices: [] + name: account_tokens + options: [] + order: 1 + customers: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: customers_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + display_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: display_name + order: 3 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + full_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 4 + size: + - 255 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + year_of_birth: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: year_of_birth + order: 5 + size: + - 0 + indices: + - fields: + - entity_id + name: customers_idx_entity_id + options: [] + type: NORMAL + name: customers + options: [] + order: 4 + entities: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: type + order: 2 + size: + - 255 + indices: [] + name: entities + options: [] + order: 2 + feedback: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: feedback_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + app_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: app_name + order: 5 + size: + - 255 + feedbacktext: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: feedbacktext + order: 4 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + package_name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: package_name + order: 6 + size: + - 255 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 2 + size: + - 0 + version_code: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_code + order: 7 + size: + - 255 + version_number: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: version_number + order: 8 + size: + - 255 + indices: + - fields: + - user_id + name: feedback_idx_user_id + options: [] + type: NORMAL + name: feedback + options: [] + order: 9 + leaderboard_sets: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - leaderboard_id + match_type: '' + name: leaderboard_sets_fk_leaderboard_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboards + type: FOREIGN KEY + fields: + date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 3 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + leaderboard_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: leaderboard_id + order: 2 + size: + - 0 + indices: + - fields: + - leaderboard_id + name: leaderboard_sets_idx_leaderboard_id + options: [] + type: NORMAL + name: leaderboard_sets + options: [] + order: 5 + leaderboard_values: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + - set_id + match_type: '' + name: leaderboard_values_entity_id_set_id + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - entity_id + match_type: '' + name: leaderboard_values_fk_entity_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - set_id + match_type: '' + name: leaderboard_values_fk_set_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: leaderboard_sets + type: FOREIGN KEY + fields: + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + position: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: position + order: 4 + size: + - 0 + set_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: set_id + order: 3 + size: + - 0 + trend: + data_type: integer + default_value: 0 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: trend + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 5 + size: + - 100 + - 0 + indices: + - fields: + - entity_id + name: leaderboard_values_idx_entity_id + options: [] + type: NORMAL + - fields: + - set_id + name: leaderboard_values_idx_set_id + options: [] + type: NORMAL + name: leaderboard_values + options: [] + order: 12 + leaderboards: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - type + match_type: '' + name: leaderboards_type + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 2 + size: + - 255 + type: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: type + order: 3 + size: + - 255 + indices: [] + name: leaderboards + options: [] + order: 3 + organisation_payroll: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - org_id + match_type: '' + name: organisation_payroll_fk_org_id + on_delete: '' + on_update: '' + options: [] + reference_fields: + - id + reference_table: organisations + type: FOREIGN KEY + fields: + employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: employee_amount + order: 5 + size: + - 0 + entry_period: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entry_period + order: 4 + size: + - 0 + gross_payroll: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: gross_payroll + order: 7 + size: + - 100 + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + local_employee_amount: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: local_employee_amount + order: 6 + size: + - 0 + org_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: org_id + order: 2 + size: + - 0 + payroll_employee_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employee_ni + order: 9 + size: + - 100 + - 0 + payroll_employer_ni: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_employer_ni + order: 10 + size: + - 100 + - 0 + payroll_income_tax: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_income_tax + order: 8 + size: + - 100 + - 0 + payroll_other_benefit: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_other_benefit + order: 12 + size: + - 100 + - 0 + payroll_total_pension: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: payroll_total_pension + order: 11 + size: + - 100 + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 3 + size: + - 0 + indices: + - fields: + - org_id + name: organisation_payroll_idx_org_id + options: [] + type: NORMAL + name: organisation_payroll + options: [] + order: 10 + organisations: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: organisations_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + country: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: country + order: 7 + size: + - 255 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + name: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: name + order: 3 + size: + - 255 + pending: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: pending + order: 9 + size: + - 0 + postcode: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: postcode + order: 6 + size: + - 16 + sector: + data_type: varchar + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: sector + order: 8 + size: + - 1 + street_name: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: street_name + order: 4 + size: + - 0 + submitted_by_id: + data_type: integer + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: submitted_by_id + order: 10 + size: + - 0 + town: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: town + order: 5 + size: + - 255 + indices: + - fields: + - entity_id + name: organisations_idx_entity_id + options: [] + type: NORMAL + name: organisations + options: [] + order: 6 + session_tokens: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - token + match_type: '' + name: session_tokens_token + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 0 + expression: '' + fields: + - user_id + match_type: '' + name: session_tokens_fk_user_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: users + type: FOREIGN KEY + fields: + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + token: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: token + order: 2 + size: + - 255 + user_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: user_id + order: 3 + size: + - 0 + indices: + - fields: + - user_id + name: session_tokens_idx_user_id + options: [] + type: NORMAL + name: session_tokens + options: [] + order: 11 + transactions: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 0 + expression: '' + fields: + - buyer_id + match_type: '' + name: transactions_fk_buyer_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + - deferrable: 0 + expression: '' + fields: + - seller_id + match_type: '' + name: transactions_fk_seller_id + on_delete: NO ACTION + on_update: NO ACTION + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + buyer_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: buyer_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + proof_image: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: proof_image + order: 5 + size: + - 0 + purchase_time: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: purchase_time + order: 7 + size: + - 0 + seller_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: seller_id + order: 3 + size: + - 0 + submitted_at: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: submitted_at + order: 6 + size: + - 0 + value: + data_type: numeric + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: value + order: 4 + size: + - 100 + - 0 + indices: + - fields: + - buyer_id + name: transactions_idx_buyer_id + options: [] + type: NORMAL + - fields: + - seller_id + name: transactions_idx_seller_id + options: [] + type: NORMAL + name: transactions + options: [] + order: 7 + users: + constraints: + - deferrable: 1 + expression: '' + fields: + - id + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: users_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - entity_id + match_type: '' + name: users_fk_entity_id + on_delete: CASCADE + on_update: '' + options: [] + reference_fields: + - id + reference_table: entities + type: FOREIGN KEY + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 3 + size: + - 0 + entity_id: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: entity_id + order: 2 + size: + - 0 + id: + data_type: integer + default_value: ~ + is_auto_increment: 1 + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: id + order: 1 + size: + - 0 + is_admin: + data_type: boolean + default_value: !!perl/ref + =: false + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: is_admin + order: 6 + size: + - 0 + join_date: + data_type: datetime + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: join_date + order: 4 + size: + - 0 + password: + data_type: varchar + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: password + order: 5 + size: + - 100 + indices: + - fields: + - entity_id + name: users_idx_entity_id + options: [] + type: NORMAL + name: users + options: [] + order: 8 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - AccountToken + - Customer + - Entity + - Feedback + - Leaderboard + - LeaderboardSet + - LeaderboardValue + - Organisation + - OrganisationPayroll + - SessionToken + - Transaction + - User + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 0.11021 diff --git a/t/api/organisation.t b/t/api/organisation.t index 2ae3fa3..8cc8cda 100644 --- a/t/api/organisation.t +++ b/t/api/organisation.t @@ -208,6 +208,24 @@ $t->post_ok('/api/v1/organisation/payroll/add' => json => { ->status_is(200)->or($framework->dump_error) ->json_is('/success', Mojo::JSON->true); +## Payroll Data List read + +$t->post_ok('/api/v1/organisation/payroll' => json => { + session_key => $session_key, + }) + ->status_is(200)->or($framework->dump_error) + ->json_is('/success', Mojo::JSON->true) + ->json_has('/payrolls') + ->json_has('/payrolls/0/entry_period') + ->json_has('/payrolls/0/employee_amount') + ->json_has('/payrolls/0/local_employee_amount') + ->json_has('/payrolls/0/gross_payroll') + ->json_has('/payrolls/0/payroll_income_tax') + ->json_has('/payrolls/0/payroll_employee_ni') + ->json_has('/payrolls/0/payroll_employer_ni') + ->json_has('/payrolls/0/payroll_total_pension') + ->json_has('/payrolls/0/payroll_other_benefit'); + ## Supplier Form submission #TODO make the test! From 22bdb625f052e281a20738fcbfb3c03fe4936016 Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 19 Sep 2017 17:40:17 +0100 Subject: [PATCH 15/15] Added datetime format --- lib/Pear/LocalLoop/Controller/Api/Transactions.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm index 79e61ad..4a0ae8c 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm @@ -35,7 +35,7 @@ sub post_transaction_list_purchases { map {{ seller => $_->seller->name, value => $_->value / 100000, - purchase_time => $_->purchase_time, + purchase_time => $c->format_iso_datetime($_->purchase_time), }} $transactions->all );