From 7ed709d1a27d3eecfa35177cf2d675e6c0bf725d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 3 Jan 2022 12:14:24 +1100 Subject: [PATCH 1/3] Tax Rate Filters --- app/Filters/TaxRateFilters.php | 115 ++++++++++++ app/Http/Controllers/TaxRateController.php | 5 +- app/Models/TaxRate.php | 4 +- tests/Feature/TaxRateApiTest.php | 197 +++++++++++++++++++++ tests/MockAccountData.php | 13 ++ 5 files changed, 331 insertions(+), 3 deletions(-) create mode 100644 app/Filters/TaxRateFilters.php create mode 100644 tests/Feature/TaxRateApiTest.php diff --git a/app/Filters/TaxRateFilters.php b/app/Filters/TaxRateFilters.php new file mode 100644 index 000000000000..59987a64c646 --- /dev/null +++ b/app/Filters/TaxRateFilters.php @@ -0,0 +1,115 @@ +builder; + } + + return $this->builder->where(function ($query) use ($filter) { + $query->where('tax_rates.name', 'like', '%'.$filter.'%'); + }); + + } + + /** + * Filters the list based on the status + * archived, active, deleted. + * + * @param string filter + * @return Builder + */ + public function status(string $filter = '') : Builder + { + if (strlen($filter) == 0) { + return $this->builder; + } + + $table = 'tax_rates'; + $filters = explode(',', $filter); + + return $this->builder->where(function ($query) use ($filters, $table) { + $query->whereNull($table.'.id'); + + if (in_array(parent::STATUS_ACTIVE, $filters)) { + $query->orWhereNull($table.'.deleted_at'); + } + + if (in_array(parent::STATUS_ARCHIVED, $filters)) { + $query->orWhere(function ($query) use ($table) { + $query->whereNotNull($table.'.deleted_at'); + + if (! in_array($table, ['users'])) { + $query->where($table.'.is_deleted', '=', 0); + } + }); + } + + if (in_array(parent::STATUS_DELETED, $filters)) { + $query->orWhere($table.'.is_deleted', '=', 1); + } + }); + } + + /** + * Sorts the list based on $sort. + * + * @param string sort formatted as column|asc + * @return Builder + */ + public function sort(string $sort) : Builder + { + $sort_col = explode('|', $sort); + + return $this->builder->orderBy($sort_col[0], $sort_col[1]); + } + + /** + * Returns the base query. + * + * @param int company_id + * @param User $user + * @return Builder + * @deprecated + */ + public function baseQuery(int $company_id, User $user) : Builder + { + return $this->builder; + } + + /** + * Filters the query by the users company ID. + * + * @return Illuminate\Database\Query\Builder + */ + public function entityFilter() + { + return $this->builder->company(); + } +} diff --git a/app/Http/Controllers/TaxRateController.php b/app/Http/Controllers/TaxRateController.php index d874aabe89ac..1b4638488bbc 100644 --- a/app/Http/Controllers/TaxRateController.php +++ b/app/Http/Controllers/TaxRateController.php @@ -12,6 +12,7 @@ namespace App\Http\Controllers; use App\Factory\TaxRateFactory; +use App\Filters\TaxRateFilters; use App\Http\Requests\TaxRate\CreateTaxRateRequest; use App\Http\Requests\TaxRate\DestroyTaxRateRequest; use App\Http\Requests\TaxRate\EditTaxRateRequest; @@ -79,9 +80,9 @@ class TaxRateController extends BaseController * * @return Response */ - public function index() + public function index(TaxRateFilters $filters) { - $tax_rates = TaxRate::scope(); + $tax_rates = TaxRate::filter($filters); return $this->listResponse($tax_rates); } diff --git a/app/Models/TaxRate.php b/app/Models/TaxRate.php index b2737c6b6cc1..5f72f75759ec 100644 --- a/app/Models/TaxRate.php +++ b/app/Models/TaxRate.php @@ -11,6 +11,7 @@ namespace App\Models; +use App\Models\Filterable; use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\SoftDeletes; @@ -18,7 +19,8 @@ class TaxRate extends BaseModel { use MakesHash; use SoftDeletes; - + use Filterable; + protected $fillable = [ 'name', 'rate', diff --git a/tests/Feature/TaxRateApiTest.php b/tests/Feature/TaxRateApiTest.php new file mode 100644 index 000000000000..a0acc34f4db7 --- /dev/null +++ b/tests/Feature/TaxRateApiTest.php @@ -0,0 +1,197 @@ +makeTestData(); + + Session::start(); + + $this->faker = \Faker\Factory::create(); + + Model::reguard(); + } + + public function testTaxRatePost() + { + $rate_name = $this->faker->firstName; + + $data = [ + 'name' => $rate_name, + 'rate' => 10 + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/tax_rates', $data); + + $arr = $response->json(); + $response->assertStatus(200); + + $this->assertEquals($rate_name, $arr['data']['name']); + + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/tax_rates/'.$arr['data']['id'], $data); + + $response->assertStatus(200); + + try{ + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/tax_rates', $data); + + $arr = $response->json(); + }catch(ValidationException $e){ + $response->assertStatus(302); + } + + $this->assertNotEmpty($arr['data']['name']); + } + + public function testTaxRatePostWithActionStart() + { + $data = [ + 'name' => $this->faker->firstName, + 'rate' => rand(1,20), + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/tax_rates', $data); + + $arr = $response->json(); + $response->assertStatus(200); + + } + + public function testTaxRatePut() + { + $data = [ + 'name' => $this->faker->firstName, + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/tax_rates/'.$this->encodePrimaryKey($this->tax_rate->id), $data); + + $response->assertStatus(200); + } + + + public function testTaxRatesGet() + { + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->get('/api/v1/tax_rates'); + + $response->assertStatus(200); + } + + + public function testTaxRateGet() + { + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->get('/api/v1/tax_rates/'.$this->encodePrimaryKey($this->tax_rate->id)); + + $response->assertStatus(200); + } + + public function testTaxRateNotArchived() + { + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->get('/api/v1/tax_rates/'.$this->encodePrimaryKey($this->tax_rate->id)); + + $arr = $response->json(); + + $this->assertEquals(0, $arr['data']['archived_at']); + } + + public function testTaxRateArchived() + { + $data = [ + 'ids' => [$this->encodePrimaryKey($this->tax_rate->id)], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/tax_rates/bulk?action=archive', $data); + + $arr = $response->json(); + + $this->assertNotNull($arr['data'][0]['archived_at']); + } + + public function testTaxRateRestored() + { + $data = [ + 'ids' => [$this->encodePrimaryKey($this->tax_rate->id)], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/tax_rates/bulk?action=restore', $data); + + $arr = $response->json(); + + $this->assertEquals(0, $arr['data'][0]['archived_at']); + } + + public function testTaxRateDeleted() + { + $data = [ + 'ids' => [$this->encodePrimaryKey($this->tax_rate->id)], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/tax_rates/bulk?action=delete', $data); + + $arr = $response->json(); + + $this->assertTrue($arr['data'][0]['is_deleted']); + } +} diff --git a/tests/MockAccountData.php b/tests/MockAccountData.php index 4056e6a828a5..7983a9d9d4de 100644 --- a/tests/MockAccountData.php +++ b/tests/MockAccountData.php @@ -42,6 +42,7 @@ use App\Models\RecurringInvoice; use App\Models\RecurringQuote; use App\Models\Task; use App\Models\TaskStatus; +use App\Models\TaxRate; use App\Models\User; use App\Models\Vendor; use App\Models\VendorContact; @@ -136,6 +137,13 @@ trait MockAccountData */ public $cu; + /** + * @var + */ + + public $tax_rate; + + /** * */ @@ -337,6 +345,11 @@ trait MockAccountData 'company_id' => $this->company->id, ]); + $this->tax_rate = TaxRate::factory()->create([ + 'user_id' => $user_id, + 'company_id' => $this->company->id, + ]); + $gs = new GroupSetting; $gs->name = 'Test'; $gs->company_id = $this->client->company_id; From f2e41b907adad918190d525ec227d3b81b4bb437 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 3 Jan 2022 12:20:03 +1100 Subject: [PATCH 2/3] Task Status Filters --- app/Http/Controllers/TaskStatusController.php | 5 +++-- app/Models/TaskStatus.php | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/TaskStatusController.php b/app/Http/Controllers/TaskStatusController.php index f83851c9d8f8..ffc6f70b01e9 100644 --- a/app/Http/Controllers/TaskStatusController.php +++ b/app/Http/Controllers/TaskStatusController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use App\Factory\TaskStatusFactory; +use App\Filters\TaskStatusFilters; use App\Http\Requests\TaskStatus\CreateTaskStatusRequest; use App\Http\Requests\TaskStatus\DestroyTaskStatusRequest; use App\Http\Requests\TaskStatus\ShowTaskStatusRequest; @@ -74,9 +75,9 @@ class TaskStatusController extends BaseController * ), * ) */ - public function index() + public function index(TaskStatusFilters $filters) { - $task_status = TaskStatus::whereCompanyId(auth()->user()->company()->id)->orWhere('company_id', null); + $task_status = TaskStatus::filter($filters); return $this->listResponse($task_status); } diff --git a/app/Models/TaskStatus.php b/app/Models/TaskStatus.php index 0b08cd792775..1b5c65d4e65e 100644 --- a/app/Models/TaskStatus.php +++ b/app/Models/TaskStatus.php @@ -11,6 +11,7 @@ namespace App\Models; +use App\Models\Filterable; use Illuminate\Database\Eloquent\SoftDeletes; /** @@ -19,7 +20,8 @@ use Illuminate\Database\Eloquent\SoftDeletes; class TaskStatus extends BaseModel { use SoftDeletes; - + use Filterable; + /** * @var bool */ From 8109ef3c50f89bb61fa2b407b166a14c5e7a9c68 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 3 Jan 2022 12:35:31 +1100 Subject: [PATCH 3/3] Company gateway Filters --- app/Filters/CompanyGatewayFilters.php | 115 ++++++++++++++++++ app/Filters/TaskStatusFilters.php | 115 ++++++++++++++++++ .../Controllers/CompanyGatewayController.php | 5 +- app/Models/CompanyGateway.php | 4 +- tests/Feature/CompanyGatewayApiTest.php | 15 +++ 5 files changed, 251 insertions(+), 3 deletions(-) create mode 100644 app/Filters/CompanyGatewayFilters.php create mode 100644 app/Filters/TaskStatusFilters.php diff --git a/app/Filters/CompanyGatewayFilters.php b/app/Filters/CompanyGatewayFilters.php new file mode 100644 index 000000000000..e2c66f43b5ab --- /dev/null +++ b/app/Filters/CompanyGatewayFilters.php @@ -0,0 +1,115 @@ +builder; + } + + return $this->builder->where(function ($query) use ($filter) { + $query->where('company_gateways.label', 'like', '%'.$filter.'%'); + }); + + } + + /** + * Filters the list based on the status + * archived, active, deleted. + * + * @param string filter + * @return Builder + */ + public function status(string $filter = '') : Builder + { + if (strlen($filter) == 0) { + return $this->builder; + } + + $table = 'company_gateways'; + $filters = explode(',', $filter); + + return $this->builder->where(function ($query) use ($filters, $table) { + $query->whereNull($table.'.id'); + + if (in_array(parent::STATUS_ACTIVE, $filters)) { + $query->orWhereNull($table.'.deleted_at'); + } + + if (in_array(parent::STATUS_ARCHIVED, $filters)) { + $query->orWhere(function ($query) use ($table) { + $query->whereNotNull($table.'.deleted_at'); + + if (! in_array($table, ['users'])) { + $query->where($table.'.is_deleted', '=', 0); + } + }); + } + + if (in_array(parent::STATUS_DELETED, $filters)) { + $query->orWhere($table.'.is_deleted', '=', 1); + } + }); + } + + /** + * Sorts the list based on $sort. + * + * @param string sort formatted as column|asc + * @return Builder + */ + public function sort(string $sort) : Builder + { + $sort_col = explode('|', $sort); + + return $this->builder->orderBy($sort_col[0], $sort_col[1]); + } + + /** + * Returns the base query. + * + * @param int company_id + * @param User $user + * @return Builder + * @deprecated + */ + public function baseQuery(int $company_id, User $user) : Builder + { + return $this->builder; + } + + /** + * Filters the query by the users company ID. + * + * @return Illuminate\Database\Query\Builder + */ + public function entityFilter() + { + return $this->builder->company(); + } +} diff --git a/app/Filters/TaskStatusFilters.php b/app/Filters/TaskStatusFilters.php new file mode 100644 index 000000000000..982edc52eaa1 --- /dev/null +++ b/app/Filters/TaskStatusFilters.php @@ -0,0 +1,115 @@ +builder; + } + + return $this->builder->where(function ($query) use ($filter) { + $query->where('task_statuses.name', 'like', '%'.$filter.'%'); + }); + + } + + /** + * Filters the list based on the status + * archived, active, deleted. + * + * @param string filter + * @return Builder + */ + public function status(string $filter = '') : Builder + { + if (strlen($filter) == 0) { + return $this->builder; + } + + $table = 'task_statuses'; + $filters = explode(',', $filter); + + return $this->builder->where(function ($query) use ($filters, $table) { + $query->whereNull($table.'.id'); + + if (in_array(parent::STATUS_ACTIVE, $filters)) { + $query->orWhereNull($table.'.deleted_at'); + } + + if (in_array(parent::STATUS_ARCHIVED, $filters)) { + $query->orWhere(function ($query) use ($table) { + $query->whereNotNull($table.'.deleted_at'); + + if (! in_array($table, ['users'])) { + $query->where($table.'.is_deleted', '=', 0); + } + }); + } + + if (in_array(parent::STATUS_DELETED, $filters)) { + $query->orWhere($table.'.is_deleted', '=', 1); + } + }); + } + + /** + * Sorts the list based on $sort. + * + * @param string sort formatted as column|asc + * @return Builder + */ + public function sort(string $sort) : Builder + { + $sort_col = explode('|', $sort); + + return $this->builder->orderBy($sort_col[0], $sort_col[1]); + } + + /** + * Returns the base query. + * + * @param int company_id + * @param User $user + * @return Builder + * @deprecated + */ + public function baseQuery(int $company_id, User $user) : Builder + { + return $this->builder; + } + + /** + * Filters the query by the users company ID. + * + * @return Illuminate\Database\Query\Builder + */ + public function entityFilter() + { + return $this->builder->company(); + } +} diff --git a/app/Http/Controllers/CompanyGatewayController.php b/app/Http/Controllers/CompanyGatewayController.php index ef5edc80cae2..f810c6e44ca0 100644 --- a/app/Http/Controllers/CompanyGatewayController.php +++ b/app/Http/Controllers/CompanyGatewayController.php @@ -13,6 +13,7 @@ namespace App\Http\Controllers; use App\DataMapper\FeesAndLimits; use App\Factory\CompanyGatewayFactory; +use App\Filters\CompanyGatewayFilters; use App\Http\Requests\CompanyGateway\CreateCompanyGatewayRequest; use App\Http\Requests\CompanyGateway\DestroyCompanyGatewayRequest; use App\Http\Requests\CompanyGateway\EditCompanyGatewayRequest; @@ -95,9 +96,9 @@ class CompanyGatewayController extends BaseController * ), * ) */ - public function index() + public function index(CompanyGatewayFilters $filters) { - $company_gateways = CompanyGateway::whereCompanyId(auth()->user()->company()->id); + $company_gateways = CompanyGateway::filter($filters); return $this->listResponse($company_gateways); } diff --git a/app/Models/CompanyGateway.php b/app/Models/CompanyGateway.php index 53a83e25275d..a31823a5541b 100644 --- a/app/Models/CompanyGateway.php +++ b/app/Models/CompanyGateway.php @@ -11,6 +11,7 @@ namespace App\Models; +use App\Models\Filterable; use App\Models\GatewayType; use App\Utils\Number; use Illuminate\Database\Eloquent\SoftDeletes; @@ -20,7 +21,8 @@ use stdClass; class CompanyGateway extends BaseModel { use SoftDeletes; - + use Filterable; + public const GATEWAY_CREDIT = 10000000; protected $casts = [ diff --git a/tests/Feature/CompanyGatewayApiTest.php b/tests/Feature/CompanyGatewayApiTest.php index 4896a3837c9d..373196c8e92b 100644 --- a/tests/Feature/CompanyGatewayApiTest.php +++ b/tests/Feature/CompanyGatewayApiTest.php @@ -167,6 +167,21 @@ class CompanyGatewayApiTest extends TestCase $cg = $response->json(); $response->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->get('/api/v1/company_gateways'); + + $response->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->get('/api/v1/company_gateways?filter=x'); + + $response->assertStatus(200); + } public function testCompanyGatewayFeesAndLimitsFails()