diff --git a/app/Http/Requests/Client/StoreClientRequest.php b/app/Http/Requests/Client/StoreClientRequest.php index fae68380e3cd..81f9540fe6f7 100644 --- a/app/Http/Requests/Client/StoreClientRequest.php +++ b/app/Http/Requests/Client/StoreClientRequest.php @@ -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. * diff --git a/app/Jobs/RecurringInvoice/SendRecurring.php b/app/Jobs/RecurringInvoice/SendRecurring.php index a5aed8e4085f..36ec516e2309 100644 --- a/app/Jobs/RecurringInvoice/SendRecurring.php +++ b/app/Jobs/RecurringInvoice/SendRecurring.php @@ -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(); diff --git a/app/Models/Client.php b/app/Models/Client.php index 0ce4b4bf0c5b..fc9137001868 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -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'; diff --git a/app/Repositories/ClientRepository.php b/app/Repositories/ClientRepository.php index 032f35d40efd..38baf89bb3cf 100644 --- a/app/Repositories/ClientRepository.php +++ b/app/Repositories/ClientRepository.php @@ -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(); diff --git a/app/Utils/Traits/GeneratesCounter.php b/app/Utils/Traits/GeneratesCounter.php index b5f302bc6b46..529bc9b3da1f 100644 --- a/app/Utils/Traits/GeneratesCounter.php +++ b/app/Utils/Traits/GeneratesCounter.php @@ -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')]; diff --git a/app/Utils/Traits/GeneratesNumberCounter.php b/app/Utils/Traits/GeneratesNumberCounter.php deleted file mode 100644 index 40bf84e16096..000000000000 --- a/app/Utils/Traits/GeneratesNumberCounter.php +++ /dev/null @@ -1,280 +0,0 @@ -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); - } - -} \ No newline at end of file diff --git a/tests/MockAccountData.php b/tests/MockAccountData.php index ac612a8e8769..96a737898887 100644 --- a/tests/MockAccountData.php +++ b/tests/MockAccountData.php @@ -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(); } diff --git a/tests/Unit/GenerateNumberTest.php b/tests/Unit/GenerateNumberTest.php deleted file mode 100644 index 4ffa306fc4c8..000000000000 --- a/tests/Unit/GenerateNumberTest.php +++ /dev/null @@ -1,214 +0,0 @@ -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'); - } -} diff --git a/tests/Unit/GeneratesCounterTest.php b/tests/Unit/GeneratesCounterTest.php new file mode 100644 index 000000000000..cc8e4ab0b045 --- /dev/null +++ b/tests/Unit/GeneratesCounterTest.php @@ -0,0 +1,43 @@ +makeTestData(); + + } + + public function testGeneric() + { + $this->assertEquals(true, true); + } + + +} \ No newline at end of file