From e4c18e734af9d13f3565c73a7d082b1c436a9242 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 11 Nov 2019 23:21:19 +1100 Subject: [PATCH] Implement fees and limits map for company gateways (#3053) * Add ability to remove group settings level company logo * Company Gateway Fees and Limits * Validation tests for FeesAndLimits * Working on company gateways * Working on transforming fees_and_limits in transformer * Implement fees and limits map for company gateways --- app/DataMapper/FeesAndLimits.php | 57 +++++++++ .../Controllers/CompanyGatewayController.php | 6 +- .../StoreCompanyGatewayRequest.php | 28 +++-- .../UpdateCompanyGatewayRequest.php | 24 ++-- .../UpdateGroupSettingRequest.php | 11 ++ .../ValidCompanyGatewayFeesAndLimitsRule.php | 55 +++++++++ app/Models/Company.php | 2 +- app/Models/CompanyGateway.php | 24 ++-- app/Repositories/GroupSettingRepository.php | 10 ++ .../CompanyGatewayTransformer.php | 22 +--- .../CompanyGatewayFeesAndLimitsSaver.php | 109 ++++++++++++++++++ .../2014_10_13_000000_create_users_table.php | 15 +-- database/seeds/RandomDataSeeder.php | 3 - tests/Feature/CompanyGatewayApiTest.php | 93 ++++++++++++++- tests/MockAccountData.php | 2 - 15 files changed, 378 insertions(+), 83 deletions(-) create mode 100644 app/DataMapper/FeesAndLimits.php create mode 100644 app/Http/ValidationRules/ValidCompanyGatewayFeesAndLimitsRule.php create mode 100644 app/Utils/Traits/CompanyGatewayFeesAndLimitsSaver.php diff --git a/app/DataMapper/FeesAndLimits.php b/app/DataMapper/FeesAndLimits.php new file mode 100644 index 0000000000..28166317ec --- /dev/null +++ b/app/DataMapper/FeesAndLimits.php @@ -0,0 +1,57 @@ + 'int', + 'min_limit' => 'float', + 'max_limit' => 'float', + 'fee_amount' => 'float', + 'fee_percent' => 'float', + 'fee_tax_name1' => 'string', + 'fee_tax_name2' => 'string', + 'fee_tax_name3' => 'string', + 'fee_tax_rate1' => 'void', + 'fee_tax_rate2' => 'float', + 'fee_tax_rate3' => 'float', + 'fee_cap' => 'float', + 'adjust_fee_percent' => 'bool', + ]; +} diff --git a/app/Http/Controllers/CompanyGatewayController.php b/app/Http/Controllers/CompanyGatewayController.php index 42f5797cf3..73f52dc416 100644 --- a/app/Http/Controllers/CompanyGatewayController.php +++ b/app/Http/Controllers/CompanyGatewayController.php @@ -192,7 +192,7 @@ class CompanyGatewayController extends BaseController */ public function store(StoreCompanyGatewayRequest $request) { - + $company_gateway = CompanyGatewayFactory::create(auth()->user()->company()->id, auth()->user()->id); $company_gateway->fill($request->all()); $company_gateway->save(); @@ -370,6 +370,10 @@ class CompanyGatewayController extends BaseController { $company_gateway->fill($request->all()); + + if(!$request->has('fees_and_limits')) + $company_gateway->fees_and_limits = ''; + $company_gateway->save(); return $this->itemResponse($company_gateway); diff --git a/app/Http/Requests/CompanyGateway/StoreCompanyGatewayRequest.php b/app/Http/Requests/CompanyGateway/StoreCompanyGatewayRequest.php index 8984aed224..f75550266c 100644 --- a/app/Http/Requests/CompanyGateway/StoreCompanyGatewayRequest.php +++ b/app/Http/Requests/CompanyGateway/StoreCompanyGatewayRequest.php @@ -12,9 +12,12 @@ namespace App\Http\Requests\CompanyGateway; use App\Http\Requests\Request; +use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule; +use App\Utils\Traits\CompanyGatewayFeesAndLimitsSaver; class StoreCompanyGatewayRequest extends Request { + use CompanyGatewayFeesAndLimitsSaver; /** * Determine if the user is authorized to make this request. * @@ -30,10 +33,12 @@ class StoreCompanyGatewayRequest extends Request public function rules() { + $this->sanitize(); $rules = [ - 'gateway_key' => 'required' + 'gateway_key' => 'required', + 'fees_and_limits' => new ValidCompanyGatewayFeesAndLimitsRule(), ]; return $rules; @@ -43,22 +48,15 @@ class StoreCompanyGatewayRequest extends Request { $input = $this->all(); - $input['config'] = encrypt($input['config']); - $input['min_limit'] = isset($input['fees_and_limits']['min_limit']) ? $input['fees_and_limits']['min_limit'] : null; - $input['max_limit'] = isset($input['fees_and_limits']['max_limit']) ? $input['fees_and_limits']['max_limit'] : null; - $input['fee_amount'] = isset($input['fees_and_limits']['fee_amount']) ? $input['fees_and_limits']['fee_amount'] : null; - $input['fee_percent'] = isset($input['fees_and_limits']['fee_percent']) ? $input['fees_and_limits']['fee_percent'] : null; - $input['fee_tax_name1'] = isset($input['fees_and_limits']['fee_tax_name1']) ? $input['fees_and_limits']['fee_tax_name1'] : ''; - $input['fee_tax_name2'] = isset($input['fees_and_limits']['fee_tax_name2']) ? $input['fees_and_limits']['fee_tax_name2'] : ''; - $input['fee_tax_name3'] = isset($input['fees_and_limits']['fee_tax_name3']) ? $input['fees_and_limits']['fee_tax_name3'] : ''; - $input['fee_tax_rate1'] = isset($input['fees_and_limits']['fee_tax_rate1']) ? $input['fees_and_limits']['fee_tax_rate1'] : 0; - $input['fee_tax_rate2'] = isset($input['fees_and_limits']['fee_tax_rate2']) ? $input['fees_and_limits']['fee_tax_rate2'] : 0; - $input['fee_tax_rate3'] = isset($input['fees_and_limits']['fee_tax_rate3']) ? $input['fees_and_limits']['fee_tax_rate3'] : 0; - $input['fee_cap'] = isset($input['fees_and_limits']['fee_cap']) ? $input['fees_and_limits']['fee_cap'] : null; - $input['adjust_fee_percent'] = isset($input['fees_and_limits']['adjust_fee_percent']) ? $input['fees_and_limits']['adjust_fee_percent'] : 0; + if(isset($input['config'])) + $input['config'] = encrypt($input['config']); + + if(isset($input['fees_and_limits'])) + $input['fees_and_limits'] = $this->cleanFeesAndLimits($input['fees_and_limits']); $this->replace($input); return $this->all(); } -} \ No newline at end of file +} + diff --git a/app/Http/Requests/CompanyGateway/UpdateCompanyGatewayRequest.php b/app/Http/Requests/CompanyGateway/UpdateCompanyGatewayRequest.php index 74c92ba4ef..0dbf6fbd36 100644 --- a/app/Http/Requests/CompanyGateway/UpdateCompanyGatewayRequest.php +++ b/app/Http/Requests/CompanyGateway/UpdateCompanyGatewayRequest.php @@ -12,10 +12,14 @@ namespace App\Http\Requests\CompanyGateway; use App\Http\Requests\Request; +use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule; use App\Models\Company; +use App\Utils\Traits\CompanyGatewayFeesAndLimitsSaver; class UpdateCompanyGatewayRequest extends Request { + use CompanyGatewayFeesAndLimitsSaver; + /** * Determine if the user is authorized to make this request. * @@ -29,33 +33,25 @@ class UpdateCompanyGatewayRequest extends Request public function rules() { + $this->sanitize(); $rules = [ + 'fees_and_limits' => new ValidCompanyGatewayFeesAndLimitsRule(), ]; return $rules; } - public function sanitize() { $input = $this->all(); $input['config'] = encrypt($input['config']); - $input['min_limit'] = isset($input['fees_and_limits']['min_limit']) ? $input['fees_and_limits']['min_limit'] : null; - $input['max_limit'] = isset($input['fees_and_limits']['max_limit']) ? $input['fees_and_limits']['max_limit'] : null; - $input['fee_amount'] = isset($input['fees_and_limits']['fee_amount']) ? $input['fees_and_limits']['fee_amount'] : null; - $input['fee_percent'] = isset($input['fees_and_limits']['fee_percent']) ? $input['fees_and_limits']['fee_percent'] : null; - $input['fee_tax_name1'] = isset($input['fees_and_limits']['fee_tax_name1']) ? $input['fees_and_limits']['fee_tax_name1'] : ''; - $input['fee_tax_name2'] = isset($input['fees_and_limits']['fee_tax_name2']) ? $input['fees_and_limits']['fee_tax_name2'] : ''; - $input['fee_tax_name3'] = isset($input['fees_and_limits']['fee_tax_name3']) ? $input['fees_and_limits']['fee_tax_name3'] : ''; - $input['fee_tax_rate1'] = isset($input['fees_and_limits']['fee_tax_rate1']) ? $input['fees_and_limits']['fee_tax_rate1'] : 0; - $input['fee_tax_rate2'] = isset($input['fees_and_limits']['fee_tax_rate2']) ? $input['fees_and_limits']['fee_tax_rate2'] : 0; - $input['fee_tax_rate3'] = isset($input['fees_and_limits']['fee_tax_rate3']) ? $input['fees_and_limits']['fee_tax_rate3'] : 0; - $input['fee_cap'] = isset($input['fees_and_limits']['fee_cap']) ? $input['fees_and_limits']['fee_cap'] : null; - $input['adjust_fee_percent'] = isset($input['fees_and_limits']['adjust_fee_percent']) ? $input['fees_and_limits']['adjust_fee_percent'] : 0; - + + if(isset($input['fees_and_limits'])) + $input['fees_and_limits'] = $this->cleanFeesAndLimits($input['fees_and_limits']); + $this->replace($input); return $this->all(); diff --git a/app/Http/Requests/GroupSetting/UpdateGroupSettingRequest.php b/app/Http/Requests/GroupSetting/UpdateGroupSettingRequest.php index 09efcdf504..31eb04ca53 100644 --- a/app/Http/Requests/GroupSetting/UpdateGroupSettingRequest.php +++ b/app/Http/Requests/GroupSetting/UpdateGroupSettingRequest.php @@ -31,6 +31,7 @@ class UpdateGroupSettingRequest extends Request public function rules() { + $this->sanitize(); $rules['settings'] = new ValidSettingsRule(); @@ -38,6 +39,16 @@ class UpdateGroupSettingRequest extends Request } + public function sanitize() + { + $input = $this->all(); + + $this->replace($input); + + return $this->all(); + + } + } \ No newline at end of file diff --git a/app/Http/ValidationRules/ValidCompanyGatewayFeesAndLimitsRule.php b/app/Http/ValidationRules/ValidCompanyGatewayFeesAndLimitsRule.php new file mode 100644 index 0000000000..e6f6d3f7fd --- /dev/null +++ b/app/Http/ValidationRules/ValidCompanyGatewayFeesAndLimitsRule.php @@ -0,0 +1,55 @@ +validateFeesAndLimits($value); + + if (is_array($data)) + { + $this->return_data = $data; + return false; + } + else + return true; + } + + /** + * @return string + */ + public function message() + { + + return $this->return_data[0]." is not a valid ".$this->return_data[1]; + + } +} diff --git a/app/Models/Company.php b/app/Models/Company.php index f2ad7e7ef0..1492fabd1f 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -141,7 +141,7 @@ class Company extends BaseModel */ public function company_gateways() { - return $this->hasMany(CompanyGateway::class)->orderBy('priority','DESC'); + return $this->hasMany(CompanyGateway::class); } /** diff --git a/app/Models/CompanyGateway.php b/app/Models/CompanyGateway.php index 4246ec04b8..df928d157c 100644 --- a/app/Models/CompanyGateway.php +++ b/app/Models/CompanyGateway.php @@ -21,6 +21,13 @@ use Illuminate\Database\Eloquent\Model; class CompanyGateway extends BaseModel { + protected $casts = [ + 'fees_and_limits' => 'object', + 'updated_at' => 'timestamp', + 'created_at' => 'timestamp', + 'deleted_at' => 'timestamp', + ]; + protected $fillable = [ 'gateway_key', 'accepted_credit_cards', @@ -29,17 +36,7 @@ class CompanyGateway extends BaseModel 'show_shipping_address', 'update_details', 'config', - 'priority', - 'min_limit', - 'max_limit', - 'fee_amount', - 'fee_percent', - 'fee_tax_name1', - 'fee_tax_name2', - 'fee_tax_rate1', - 'fee_tax_rate2', - 'fee_cap', - 'adjust_fee_percent', + 'fees_and_limits', ]; public static $credit_cards = [ @@ -50,6 +47,11 @@ class CompanyGateway extends BaseModel 16 => ['card' => 'images/credit_cards/Test-Discover-Icon.png', 'text' => 'Discover'], ]; + // public function getFeesAndLimitsAttribute() + // { + // return json_decode($this->attributes['fees_and_limits']); + // } + public function company() { return $this->belongsTo(Company::class); diff --git a/app/Repositories/GroupSettingRepository.php b/app/Repositories/GroupSettingRepository.php index 1f93abb38f..1bf1942b27 100644 --- a/app/Repositories/GroupSettingRepository.php +++ b/app/Repositories/GroupSettingRepository.php @@ -36,6 +36,16 @@ class GroupSettingRepository $group_setting->fill($data); $group_setting->save(); + if(array_key_exists('company_logo', $data) && $data['company_logo'] == '') + { + + $settings = $group_setting->settings; + unset($settings->company_logo); + $group_setting->settings = $settings; + $group_setting->save(); + + } + return $group_setting; } diff --git a/app/Transformers/CompanyGatewayTransformer.php b/app/Transformers/CompanyGatewayTransformer.php index 433f6233ce..9be121f12f 100644 --- a/app/Transformers/CompanyGatewayTransformer.php +++ b/app/Transformers/CompanyGatewayTransformer.php @@ -52,8 +52,7 @@ class CompanyGatewayTransformer extends EntityTransformer 'show_shipping_address' => (bool)$company_gateway->show_shipping_address, 'update_details' => (bool)$company_gateway->update_details, 'config' => (string) $company_gateway->getConfigTransformed(), - //'priority' => (int)$company_gateway->priority, - 'fees_and_limits' => $this->mapFeesAndLimits($company_gateway), + 'fees_and_limits' => $company_gateway->fees_and_limits ?: '', 'updated_at' => $company_gateway->updated_at, 'deleted_at' => $company_gateway->deleted_at, ]; @@ -66,23 +65,4 @@ class CompanyGatewayTransformer extends EntityTransformer return $this->includeItem($company_gateway->gateway, $transformer, Gateway::class); } - - private function mapFeesAndLimits($company_gateway) - { - $cg = new \stdClass; - $cg->min_limit = (float)$company_gateway->min_limit ?: null; - $cg->max_limit = (float)$company_gateway->max_limit ?: null; - $cg->fee_amount = (float) $company_gateway->fee_amount ?: null; - $cg->fee_percent = (float)$company_gateway->fee_percent ?: null; - $cg->fee_tax_name1 = (string)$company_gateway->fee_tax_name1 ?: ''; - $cg->fee_tax_name2 = (string) $company_gateway->fee_tax_name2 ?: ''; - $cg->fee_tax_name3 = (string) $company_gateway->fee_tax_name3 ?: ''; - $cg->fee_tax_rate1 = (float) $company_gateway->fee_tax_rate1; - $cg->fee_tax_rate2 = (float)$company_gateway->fee_tax_rate2; - $cg->fee_tax_rate3 = (float)$company_gateway->fee_tax_rate3; - $cg->fee_cap = (float)$company_gateway->fee_cap ?: null; - $cg->adjust_fee_percent = (bool)$company_gateway->adjust_fee_percent; - - return $cg; - } } diff --git a/app/Utils/Traits/CompanyGatewayFeesAndLimitsSaver.php b/app/Utils/Traits/CompanyGatewayFeesAndLimitsSaver.php new file mode 100644 index 0000000000..05c676fff4 --- /dev/null +++ b/app/Utils/Traits/CompanyGatewayFeesAndLimitsSaver.php @@ -0,0 +1,109 @@ + $value) + { + + + /* Handles unset settings or blank strings */ + if(!property_exists($fee_and_limit, $key) || is_null($fee_and_limit->{$key}) || !isset($fee_and_limit->{$key}) || $fee_and_limit->{$key} == '') + continue; + + /*Catch all filter */ + if(!$this->checkAttribute($value, $fee_and_limit->{$key})) + return [$key, $value]; + + } + + } + + return true; + } + + /** + * Type checks a object property. + * @param string $key The type + * @param string $value The object property + * @return bool TRUE if the property is the expected type + */ + private function checkAttribute($key, $value) :bool + { + switch ($key) + { + case 'int': + case 'integer': + return ctype_digit(strval($value)); + case 'real': + case 'float': + case 'double': + return is_float($value) || is_numeric(strval($value)); + case 'string': + return method_exists($value, '__toString' ) || is_null($value) || is_string($value); + case 'bool': + case 'boolean': + return is_bool($value) || (int) filter_var($value, FILTER_VALIDATE_BOOLEAN); + case 'object': + return is_object($value); + case 'array': + return is_array($value); + case 'json': + json_decode($string); + return (json_last_error() == JSON_ERROR_NONE); + default: + return false; + } + } + + public function cleanFeesAndLimits($fees_and_limits) + { + $new_arr = []; + + foreach($fees_and_limits as $key => $value) + { + + $fal = new FeesAndLimits; + + foreach($value as $k => $v) + { + $fal->{$k} = $v; + } + + $new_arr[$key] = (array)$fal; + + } + + return $new_arr; + + } + +} \ No newline at end of file diff --git a/database/migrations/2014_10_13_000000_create_users_table.php b/database/migrations/2014_10_13_000000_create_users_table.php index 29ceadfbc5..47f5cfeab6 100644 --- a/database/migrations/2014_10_13_000000_create_users_table.php +++ b/database/migrations/2014_10_13_000000_create_users_table.php @@ -379,20 +379,7 @@ class CreateUsersTable extends Migration $table->boolean('show_shipping_address')->default(true)->nullable(); $table->boolean('update_details')->default(false)->nullable(); $table->text('config'); - $table->unsignedInteger('priority')->default(0); - - $table->decimal('min_limit', 16, 4)->nullable(); - $table->decimal('max_limit', 16, 4)->nullable(); - $table->decimal('fee_amount', 16, 4)->nullable(); - $table->decimal('fee_percent', 16, 4)->nullable(); - $table->string('fee_tax_name1')->nullable(); - $table->string('fee_tax_name2')->nullable(); - $table->string('fee_tax_name3')->nullable(); - $table->decimal('fee_tax_rate1', 16, 4)->nullable(); - $table->decimal('fee_tax_rate2', 16, 4)->nullable(); - $table->decimal('fee_tax_rate3', 16, 4)->nullable(); - $table->unsignedInteger('fee_cap')->nullable(); - $table->boolean('adjust_fee_percent')->default(false); + $table->text('fees_and_limits'); $table->timestamps(6); $table->softDeletes(); diff --git a/database/seeds/RandomDataSeeder.php b/database/seeds/RandomDataSeeder.php index 23dcd66665..11813e49ad 100644 --- a/database/seeds/RandomDataSeeder.php +++ b/database/seeds/RandomDataSeeder.php @@ -198,7 +198,6 @@ class RandomDataSeeder extends Seeder $cg->show_shipping_address = true; $cg->update_details = true; $cg->config = encrypt(config('ninja.testvars.stripe')); - $cg->priority = 1; $cg->save(); $cg = new CompanyGateway; @@ -210,7 +209,6 @@ class RandomDataSeeder extends Seeder $cg->show_shipping_address = true; $cg->update_details = true; $cg->config = encrypt(config('ninja.testvars.stripe')); - $cg->priority = 2; $cg->save(); } @@ -225,7 +223,6 @@ class RandomDataSeeder extends Seeder $cg->show_shipping_address = true; $cg->update_details = true; $cg->config = encrypt(config('ninja.testvars.paypal')); - $cg->priority = 3; $cg->save(); } diff --git a/tests/Feature/CompanyGatewayApiTest.php b/tests/Feature/CompanyGatewayApiTest.php index 832c0c2eac..6eef98f3f2 100644 --- a/tests/Feature/CompanyGatewayApiTest.php +++ b/tests/Feature/CompanyGatewayApiTest.php @@ -3,11 +3,13 @@ namespace Tests\Feature; use App\DataMapper\DefaultSettings; +use App\DataMapper\FeesAndLimits; use App\Models\Account; use App\Models\Client; use App\Models\ClientContact; use App\Models\Company; use App\Models\User; +use App\Utils\Traits\CompanyGatewayFeesAndLimitsSaver; use App\Utils\Traits\MakesHash; use Faker\Factory; use Illuminate\Database\Eloquent\Model; @@ -28,7 +30,7 @@ class CompanyGatewayApiTest extends TestCase use MakesHash; use DatabaseTransactions; use MockAccountData; - + use CompanyGatewayFeesAndLimitsSaver; public function setUp() :void { @@ -115,4 +117,93 @@ class CompanyGatewayApiTest extends TestCase } + + public function testCompanyGatewayFeesAndLimitsSuccess() + { + $fee = new FeesAndLimits; + + $fee = (array)$fee; + + $fee_and_limit['1'] = ['min_limit' => 1]; + $fee_and_limit['2'] = ['min_limit' => 1]; + $fee_and_limit['3'] = ['min_limit' => 1]; + $fee_and_limit['4'] = ['min_limit' => 1]; + $fee_and_limit['5'] = ['min_limit' => 1]; + + $data = [ + 'config' => 'random config', + 'gateway_key' => '3b6621f970ab18887c4f6dca78d3f8bb', + 'fees_and_limits' => $fee_and_limit, + ]; + + /* POST */ + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token + ])->post('/api/v1/company_gateways', $data); + + $cg = $response->json(); + + $cg_id = $cg['data']['id']; + + $this->assertNotNull($cg_id); + + $cg_fee = $cg['data']['fees_and_limits']; + + $this->assertNotNull($cg_fee); + + $response->assertStatus(200); + + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token + ])->get('/api/v1/company_gateways/'.$this->encodePrimaryKey($cg['data']['id'])); + + $cg = $response->json(); + + $response->assertStatus(200); + + + } + + + public function testCompanyGatewayFeesAndLimitsFails() + { + $fee_and_limit['bank_transfer'] = new FeesAndLimits; + + $fee_and_limit['bank_transfer']->adjust_fee_percent = 10; + + $data = [ + 'config' => 'random config', + 'gateway_key' => '3b6621f970ab18887c4f6dca78d3f8bb', + 'fees_and_limits' => $fee_and_limit, + ]; + + /* POST */ + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token + ])->post('/api/v1/company_gateways', $data); + + + $response->assertStatus(302); + + } + + public function testCompanyGatewayArrayBuilder() + { + $arr = [ + 'min_limit' => 1, + 'max_limit' => 2 + ]; + + $fal = (array)new FeesAndLimits; + + $new_arr = array_replace($fal, $arr); + + $this->assertEquals($arr['min_limit'], $new_arr['min_limit']); + $this->assertTrue(array_key_exists('fee_amount', $new_arr)); + + } } \ No newline at end of file diff --git a/tests/MockAccountData.php b/tests/MockAccountData.php index 493fcf7fa6..be2ca8c978 100644 --- a/tests/MockAccountData.php +++ b/tests/MockAccountData.php @@ -196,7 +196,6 @@ trait MockAccountData $cg->show_shipping_address = true; $cg->update_details = true; $cg->config = encrypt(config('ninja.testvars.stripe')); - $cg->priority = 1; $cg->save(); @@ -209,7 +208,6 @@ trait MockAccountData $cg->show_shipping_address = true; $cg->update_details = true; $cg->config = encrypt(config('ninja.testvars.stripe')); - $cg->priority = 2; $cg->save(); }