Working on tests for new GeneratesCounterTest

This commit is contained in:
David Bomba 2019-05-27 20:48:52 +10:00
parent 0a12e2d49a
commit 494504a2d0
9 changed files with 82 additions and 524 deletions

View File

@ -13,11 +13,9 @@ namespace App\Http\Requests\Client;
use App\Http\Requests\Request;
use App\Models\Client;
use App\Utils\Traits\GeneratesNumberCounter;
class StoreClientRequest extends Request
{
use GeneratesNumberCounter;
/**
* Determine if the user is authorized to make this request.
*

View File

@ -14,7 +14,7 @@ namespace App\Jobs\RecurringInvoice;
use App\Factory\RecurringInvoiceToInvoiceFactory;
use App\Models\Invoice;
use App\Models\RecurringInvoice;
use App\Utils\Traits\GeneratesNumberCounter;
use App\Utils\Traits\GeneratesCounter;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
@ -22,8 +22,8 @@ use Illuminate\Support\Facades\Log;
class SendRecurring
{
use GeneratesNumberCounter;
use GeneratesCounter;
public $recurring_invoice;
protected $db;
@ -53,7 +53,7 @@ class SendRecurring
// Generate Standard Invoice
$invoice = RecurringInvoiceToInvoiceFactory::create($this->recurring_invoice);
$invoice->invoice_number = $this->getNextNumber($invoice);
$invoice->invoice_number = $this->getNextInvoiceNumber($this->recurring_invoice->client);
$invoice->status_id = Invoice::STATUS_SENT;
$invoice->save();

View File

@ -18,7 +18,6 @@ use App\Models\Company;
use App\Models\Country;
use App\Models\Filterable;
use App\Models\Timezone;
use App\Utils\Traits\GeneratesNumberCounter;
use App\Utils\Traits\MakesDates;
use App\Utils\Traits\MakesHash;
use Hashids\Hashids;
@ -33,7 +32,6 @@ class Client extends BaseModel
use MakesDates;
use SoftDeletes;
use Filterable;
use GeneratesNumberCounter;
protected $presenter = 'App\Models\Presenters\ClientPresenter';

View File

@ -13,6 +13,7 @@ namespace App\Repositories;
use App\Models\Client;
use App\Repositories\ClientContactRepository;
use App\Utils\Traits\GeneratesCounter;
use Illuminate\Http\Request;
/**
@ -20,7 +21,7 @@ use Illuminate\Http\Request;
*/
class ClientRepository extends BaseRepository
{
use GeneratesCounter;
/**
* @var ClientContactRepository
*/
@ -64,7 +65,7 @@ class ClientRepository extends BaseRepository
$client->save();
$client->id_number = $client->getNextNumber($client); //todo write tests for this and make sure that custom client numbers also works as expected from here
$client->id_number = $this->getNextClientNumber($client); //todo write tests for this and make sure that custom client numbers also works as expected from here
$client->save();

View File

@ -23,7 +23,7 @@ use Illuminate\Support\Facades\Log;
* Class GeneratesCounter
* @package App\Utils\Traits
*/
trait GeneratesNumberCounter
trait GeneratesCounter
{
public function getNextInvoiceNumber(Client $client)
@ -40,6 +40,7 @@ trait GeneratesNumberCounter
//build number pattern
$invoice_number = $this->applyNumberPattern($client, $counter, $client_counter, $client->company->settings->invoice_number_pattern);
return $invoice_number;
}
public function getNextCreditNumber()
@ -62,9 +63,17 @@ trait GeneratesNumberCounter
}
public function getNextClientNumber()
public function getNextClientNumber(Client $client)
{
//Reset counters if enabled
$this->resetCounters($client);
$counter = $client->company->getSettingsByKey( 'client_number_counter' );
$counter = $this->checkEntityNumber($client, $counter, $client->company->settings->counter_padding, $client->company->settings->client_number_prefix);
$client_number = $this->applyNumberPattern($client, $counter, $counter, $client->company->settings->client_number_pattern);
return $client_number;
}
@ -87,13 +96,15 @@ trait GeneratesNumberCounter
$number = $this->padCounter($counter, $padding);
$number = $this->prefixCounter($number, $prefix);
$check = $entity::company($entity->company_id)->whereIdNumber($number)->withTrashed()->first();
$class = get_class($entity);
$check = $class::whereCompanyId($entity->company_id)->whereIdNumber($number)->withTrashed()->first();
$counter++;
} while ($check);
$this->incrementCounter($client, 'invoice_number_counter');
$this->incrementCounter($entity, 'invoice_number_counter');
return $number;
}
@ -105,17 +116,17 @@ trait GeneratesNumberCounter
* @param \App\Models\Client $client The client
* @param \App\Models\Client|integer|string $counter_name The counter name
*/
private function incrementCounter(Client $client, string $counter_name) :void
private function incrementCounter($entity, string $counter_name) :void
{
$company_settings = $client->company->settings;
$company_settings = $entity->company->settings;
$company_settings->$counter_name = $company_settings->$counter_name + 1;
$client->company->settings = $company_settings;
$client->company->save();
$entity->company->settings = $company_settings;
$entity->company->save();
$client_settings = $client->settings;
$client_settings = $entity->settings;
$client_settings->$counter_name = $client_settings->$counter_name + 1;
$client->settings = $client_settings;
$client->save();
$entity->settings = $client_settings;
$entity->save();
}
private function prefixCounter($counter, $prefix) : string
@ -231,7 +242,7 @@ trait GeneratesNumberCounter
private function applyNumberPattern($client, $counter, $client_counter, $pattern)
{
if(!$pattern)
return $counter;
return $counter;
$search = ['{$year}'];
$replace = [date('Y')];

View File

@ -1,280 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Utils\Traits;
use App\Models\Client;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\Quote;
use App\Models\RecurringInvoice;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
/**
* Class GeneratesNumberCounter
* @package App\Utils\Traits
*/
trait GeneratesNumberCounter
{
public function getNextNumber($entity)
{
$entity_name = $this->entityName($entity);
$counter = $this->getCounter($entity);
$counter_offset = 0;
$prefix = $this->getNumberPrefix($entity);
$lastNumber = false;
$check = false;
do {
if ($this->hasNumberPattern($entity)) {
$number = $this->applyNumberPattern($entity, $counter);
} else {
$number = $prefix . str_pad($counter, $entity->getSettingsByKey('counter_padding'), '0', STR_PAD_LEFT);
}
if ($entity_name == Client::class) {
$check = Client::company($this->company_id)->whereIdNumber($number)->withTrashed()->first();
} elseif ($entity_name == Invoice::class) {
$check = Invoice::company($this->company_id)->whereInvoiceNumber($number)->withTrashed()->first();
} elseif ($entity_name == Quote::class) {
$check = Quote::company($this->company_id)->whereQuoteNumber($number)->withTrashed()->first();
} elseif ($entity_name == Credit::class) {
$check = Credit::company($this->company_id)->whereCreditNumber($number)->withTrashed()->first();
}
$counter++;
$counter_offset++; //?
// prevent getting stuck in a loop
if ($number == $lastNumber) {
return '';
}
$lastNumber = $number;
} while ($check);
$this->incrementCounter($entity);
return $number;
//increment the counter here
}
/**
* Determines if it has shared counter.
*
* @param object $entity The entity
*
* @return boolean True if has shared counter, False otherwise.
*/
public function hasSharedCounter($entity) : bool
{
return $entity->getSettingsByKey('shared_invoice_quote_counter') === TRUE;
}
/**
* @param $entity
*
* @return bool
*/
public function hasNumberPattern($entity) : bool
{
return $this->getNumberPattern($entity) ? true : false;
}
/**
* @param $entity
*
* @return NULL|string
*/
public function getNumberPattern($entity)
{
$entity_name = $this->entityName($entity);
/** Recurring invoice share the same number pattern as invoices */
if($entity_name == $this->entityName(RecurringInvoice::class) )
$entity_name = $this->entityName(Invoice::class);
$field = $entity_name . "_number_pattern";
return $entity->getSettingsByKey( $field );
}
/**
* @param $entity
*
* @return string
*/
public function getNumberPrefix($entity)
{
$entity_name = $this->entityName($entity);
$field = $this->entityName($entity_name) . "_number_prefix";
return $entity->getSettingsByKey( $field );
}
public function incrementCounter($entity)
{
$counter = $this->getCounterName($entity) . '_number_counter';
//Log::error('entity = '.$entity_name);
$entity_settings = $entity->getSettingsByKey( $counter );
//Log::error(print_r($entity_settings,1));
$entity_settings->$counter = $entity_settings->$counter + 1;
// Log::error('name '.$counter);
// Log::error('key '.$entity_settings->$counter);
// Log::error('value '.$entity_settings->{$counter});
// Log::error('value inc '.$entity_settings->{$counter}++);
//Log::error($entity_settings->{$counter});
Log::error('entity name = '.$entity_settings->entity);
$entity->setSettingsByEntity($entity_settings->entity, $entity_settings);
//Log::error(print_r($entity_settings,1));
}
private function entityName($entity)
{
return strtolower(snake_case(class_basename($entity)));
}
public function getCounter($entity) : int
{
//company specific settings need to fall back to COMPANY not $entity
$counter = $this->getCounterName($entity) . '_number_counter';
if($counter == 'client_number_counter')
return $entity->company->getSettingsByKey( $counter );
else
return $entity->getSettingsByKey( $counter );
}
/**
* @param $entity
* @param mixed $counter
* todo localize PHP date
* @return bool|mixed
*/
public function applyNumberPattern($entity, $counter = 1)
{
$entity_name = $this->entityName($entity);
$counter = $counter ?: $this->getCounter($entity_name);
$pattern = $this->getNumberPattern($entity);
if (! $pattern) {
return false;
}
$search = ['{$year}'];
$replace = [date('Y')];
$search[] = '{$counter}';
$replace[] = str_pad($counter, $entity->getSettingsByKey( 'counter_padding' ), '0', STR_PAD_LEFT);
if (strstr($pattern, '{$user_id}')) {
$user_id = auth()->check() ? auth()->user()->id : 0;
$search[] = '{$user_id}';
$replace[] = str_pad(($user_id), 2, '0', STR_PAD_LEFT);
}
$matches = false;
preg_match('/{\$date:(.*?)}/', $pattern, $matches);
if (count($matches) > 1) {
$format = $matches[1];
$search[] = $matches[0];
/* The following adjusts for the company timezone - may bork tests depending on the time of day the tests are run!!!!!!*/
$date = Carbon::now($entity->company->timezone()->name)->format($format);
$replace[] = str_replace($format, $date, $matches[1]);
}
$pattern = str_replace($search, $replace, $pattern);
$pattern = $this->getClientInvoiceNumber($pattern, $entity);
return $pattern;
}
private function getClientInvoiceNumber($pattern, $entity)
{
$entity_name = $this->entityName($entity);
if ($entity_name == $this->entityName(Client::class) || $entity_name == $this->entityName(Credit::class) || ! $entity->client_id)
{
return $pattern;
}
$search = [
'{$custom1}',
'{$custom2}',
'{$idNumber}',
'{$clientCustom1}',
'{$clientCustom2}',
'{$clientIdNumber}',
'{$clientCounter}',
];
$counter = $this->getCounterName($entity) . '_number_counter';
$counter_value = $entity->client->getSettingsByKey( $counter );
$entity_padding = $this->getSettingsByKey( 'counter_padding' );
$replace = [
$this->custom_value1,
$this->custom_value2,
$this->id_number,
$this->custom_value1, // backwards compatibility
$this->custom_value2,
$this->id_number,
str_pad($counter_value, $entity_padding, '0', STR_PAD_LEFT),
];
return str_replace($search, $replace, $pattern);
}
private function getCounterName($entity)
{
if($this->entityName($entity) == $this->entityName(RecurringInvoice::class) || ( $this->entityName($entity) == $this->entityName(Quote::class) && $this->hasSharedCounter($entity)) )
$entity = Invoice::class;
return $this->entityName($entity);
}
}

View File

@ -22,7 +22,7 @@ use App\Models\Credit;
use App\Models\Invoice;
use App\Models\Quote;
use App\Models\RecurringInvoice;
use App\Utils\Traits\GeneratesNumberCounter;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\MakesHash;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
@ -35,7 +35,8 @@ trait MockAccountData
{
use MakesHash;
use GeneratesNumberCounter;
use GeneratesCounter;
public $account;
public $company;
@ -94,7 +95,7 @@ trait MockAccountData
$recurring_invoice->start_date = Carbon::now()->format('Y-m-d');
$recurring_invoice->save();
$recurring_invoice->invoice_number = $this->getNextNumber($recurring_invoice);
$recurring_invoice->invoice_number = $this->getNextInvoiceNumber($this->invoice->client);
$recurring_invoice->save();
$recurring_invoice = InvoiceToRecurringInvoiceFactory::create($this->invoice);
@ -104,7 +105,7 @@ trait MockAccountData
$recurring_invoice->start_date = Carbon::now()->format('Y-m-d');
$recurring_invoice->save();
$recurring_invoice->invoice_number = $this->getNextNumber($recurring_invoice);
$recurring_invoice->invoice_number = $this->getNextInvoiceNumber($this->invoice->client);
$recurring_invoice->save();
$recurring_invoice = InvoiceToRecurringInvoiceFactory::create($this->invoice);
@ -114,7 +115,7 @@ trait MockAccountData
$recurring_invoice->start_date = Carbon::now()->format('Y-m-d');
$recurring_invoice->save();
$recurring_invoice->invoice_number = $this->getNextNumber($recurring_invoice);
$recurring_invoice->invoice_number = $this->getNextInvoiceNumber($this->invoice->client);
$recurring_invoice->save();
$recurring_invoice = InvoiceToRecurringInvoiceFactory::create($this->invoice);
@ -124,7 +125,7 @@ trait MockAccountData
$recurring_invoice->start_date = Carbon::now()->format('Y-m-d');
$recurring_invoice->save();
$recurring_invoice->invoice_number = $this->getNextNumber($recurring_invoice);
$recurring_invoice->invoice_number = $this->getNextInvoiceNumber($this->invoice->client);
$recurring_invoice->save();
@ -135,7 +136,7 @@ trait MockAccountData
$recurring_invoice->start_date = Carbon::now()->format('Y-m-d');
$recurring_invoice->save();
$recurring_invoice->invoice_number = $this->getNextNumber($recurring_invoice);
$recurring_invoice->invoice_number = $this->getNextInvoiceNumber($this->invoice->client);
$recurring_invoice->save();
$recurring_invoice = InvoiceToRecurringInvoiceFactory::create($this->invoice);
@ -145,7 +146,7 @@ trait MockAccountData
$recurring_invoice->start_date = Carbon::now()->format('Y-m-d');
$recurring_invoice->save();
$recurring_invoice->invoice_number = $this->getNextNumber($recurring_invoice);
$recurring_invoice->invoice_number = $this->getNextInvoiceNumber($this->invoice->client);
$recurring_invoice->save();
}

View File

@ -1,214 +0,0 @@
<?php
namespace Tests\Unit;
use App\DataMapper\DefaultSettings;
use App\Models\Client;
use App\Models\Company;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\RecurringInvoice;
use App\Utils\Traits\GeneratesNumberCounter;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Session;
use Tests\TestCase;
/**
* @test
* @covers App\Utils\Traits\GeneratesNumberCounter
*/
class GenerateNumberTest extends TestCase
{
use GeneratesNumberCounter;
use MakesHash;
use DatabaseTransactions;
public function setUp() :void
{
parent::setUp();
Session::start();
$this->faker = \Faker\Factory::create();
Model::reguard();
$account = factory(\App\Models\Account::class)->create();
$company = factory(\App\Models\Company::class)->create([
'account_id' => $account->id,
]);
$account->default_company_id = $company->id;
$account->save();
$user = factory(\App\Models\User::class)->create([
// 'account_id' => $account->id,
'confirmation_code' => $this->createDbHash(config('database.default'))
]);
$userPermissions = collect([
'view_invoice',
'view_client',
'edit_client',
'edit_invoice',
'create_invoice',
'create_client'
]);
$userSettings = DefaultSettings::userSettings();
$user->companies()->attach($company->id, [
'account_id' => $account->id,
'is_owner' => 1,
'is_admin' => 1,
'permissions' => $userPermissions->toJson(),
'settings' => json_encode($userSettings),
'is_locked' => 0,
]);
factory(\App\Models\Client::class)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company){
factory(\App\Models\ClientContact::class,1)->create([
'user_id' => $user->id,
'client_id' => $c->id,
'company_id' => $company->id,
'is_primary' => 1
]);
factory(\App\Models\ClientContact::class,2)->create([
'user_id' => $user->id,
'client_id' => $c->id,
'company_id' => $company->id
]);
});
$this->client = Client::whereUserId($user->id)->whereCompanyId($company->id)->first();
}
public function testEntityName()
{
$this->assertEquals($this->entityName($this->client), 'client');
}
public function testSharedCounter()
{
$this->assertFalse($this->hasSharedCounter($this->client));
}
public function testClientCounterValue()
{
$this->assertEquals($this->getCounter($this->client), 1);
}
public function testClientNextNumber()
{
$this->assertEquals($this->getNextNumber($this->client),1);
}
public function testRecurringInvoiceNumberPrefix()
{
//$this->assertEquals($this->getNextNumber(RecurringInvoice::class), 'R1');
$this->assertEquals($this->getCounter($this->client), 1);
}
public function testClientIncrementer()
{
$this->incrementCounter($this->client);
$this->assertEquals($this->getCounter($this->client), 2);
}
/*
public function testCounterValues()
{
$this->assertEquals($this->getCounter(Invoice::class), 1);
$this->assertEquals($this->getCounter(RecurringInvoice::class), 1);
$this->assertEquals($this->getCounter(Credit::class), 1);
}
public function testClassIncrementers()
{
$this->client->incrementCounter(Invoice::class);
$this->client->incrementCounter(RecurringInvoice::class);
$this->client->incrementCounter(Credit::class);
$this->assertEquals($this->getCounter(Invoice::class), 3);
$this->assertEquals($this->getCounter(RecurringInvoice::class), 3);
$this->assertEquals($this->getCounter(Credit::class), 2);
}
*/
/**
* {$counter}
* {$userId}
* {$year}
* {$date:format} - See options
* @return [type] [description]
*/
public function testClientNumberPattern()
{
$settings = $this->client->getSettingsByKey('client_number_pattern');
$settings->client_number_pattern = '{$year}-{$counter}';
$this->client->setSettingsByEntity(Client::class, $settings);
$company = Company::find($this->client->company_id);
$this->assertEquals($company->settings->client_number_counter,1);
$this->assertEquals($this->getNextNumber($this->client), '2019-1');
$this->assertEquals($this->getNextNumber($this->client), '2019-2');
$company = Company::find($this->client->company_id);
$this->assertEquals($company->settings->client_number_counter,2);
$this->assertEquals($this->client->settings->client_number_counter,1);
}
public function testClientNumberPatternWithDate()
{
date_default_timezone_set('US/Eastern');
$settings = $this->client->getSettingsByKey('client_number_pattern');
$settings->client_number_pattern = '{$date:j}-{$counter}';
$this->client->setSettingsByEntity(Client::class, $settings);
$this->assertEquals($this->getNextNumber($this->client), date('j') . '-1');
}
public function testClientNumberPatternWithDate2()
{
date_default_timezone_set('US/Eastern');
$settings = $this->client->getSettingsByKey('client_number_pattern');
$settings->client_number_pattern = '{$date:d M Y}-{$counter}';
$this->client->setSettingsByEntity(Client::class, $settings);
$this->assertEquals($this->getNextNumber($this->client), date('d M Y') . '-1');
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace Tests\Unit;
use App\DataMapper\DefaultSettings;
use App\Models\Client;
use App\Models\Company;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\RecurringInvoice;
use App\Utils\Traits\GeneratesCounter;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Session;
use Tests\MockAccountData;
use Tests\TestCase;
/**
* @test
* @covers App\Utils\Traits\GeneratesCounter
*/
class GeneratesCounterTest extends TestCase
{
use DatabaseTransactions;
use MockAccountData;
public function setUp() :void
{
parent::setUp();
$this->makeTestData();
}
public function testGeneric()
{
$this->assertEquals(true, true);
}
}