Improve invoice number generation when race conditions encountered

This commit is contained in:
David Bomba 2022-04-07 17:40:59 +10:00
parent ee6f2012f6
commit 4f10dcd913
7 changed files with 214 additions and 95 deletions

View File

@ -1,85 +0,0 @@
<?php
/**
* Quote Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Quote Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Jobs\Quote;
use App\Libraries\MultiDB;
use App\Models\Company;
use App\Models\Quote;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\NumberFormatter;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ApplyQuoteNumber implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, NumberFormatter, GeneratesCounter;
private $quote;
private $settings;
private $company;
/**
* Create a new job instance.
*
* @param Quote $quote
* @param $settings
* @param Company $company
*/
public function __construct(Quote $quote, $settings, Company $company)
{
$this->quote = $quote;
$this->settings = $settings;
$this->company = $company;
}
/**
* Execute the job.
*
*
* @return Quote
*/
public function handle()
{
MultiDB::setDB($this->company->db);
//return early
if ($this->quote->number != '') {
return $this->quote;
}
switch ($this->settings->quote_number_applied) {
case 'when_saved':
$this->quote->number = $this->getNextQuoteNumber($this->quote->client, $this->quote);
break;
case 'when_sent':
if ($this->quote->status_id == Quote::STATUS_SENT) {
$this->quote->number = $this->getNextQuoteNumber($this->quote->client, $this->quote);
}
break;
default:
// code...
break;
}
$this->quote->save();
return $this->quote;
}
}

View File

@ -15,6 +15,7 @@ use App\Models\Client;
use App\Models\Credit; use App\Models\Credit;
use App\Services\AbstractService; use App\Services\AbstractService;
use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\GeneratesCounter;
use Illuminate\Database\QueryException;
class ApplyNumber extends AbstractService class ApplyNumber extends AbstractService
{ {
@ -24,6 +25,8 @@ class ApplyNumber extends AbstractService
private $credit; private $credit;
private bool $completed = true;
public function __construct(Client $client, Credit $credit) public function __construct(Client $client, Credit $credit)
{ {
$this->client = $client; $this->client = $client;
@ -37,8 +40,40 @@ class ApplyNumber extends AbstractService
return $this->credit; return $this->credit;
} }
$this->credit->number = $this->getNextCreditNumber($this->client, $this->credit); $this->trySaving();
// $this->credit->number = $this->getNextCreditNumber($this->client, $this->credit);
return $this->credit; return $this->credit;
} }
private function trySaving()
{
$x=1;
do{
try{
$this->credit->number = $this->getNextCreditNumber($this->client, $this->credit);
$this->credit->saveQuietly();
$this->completed = false;
}
catch(QueryException $e){
$x++;
if($x>10)
$this->completed = false;
}
}
while($this->completed);
}
} }

View File

@ -15,6 +15,7 @@ use App\Models\Client;
use App\Models\Invoice; use App\Models\Invoice;
use App\Services\AbstractService; use App\Services\AbstractService;
use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\GeneratesCounter;
use Illuminate\Database\QueryException;
class ApplyNumber extends AbstractService class ApplyNumber extends AbstractService
{ {
@ -24,6 +25,8 @@ class ApplyNumber extends AbstractService
private $invoice; private $invoice;
private $completed = true;
public function __construct(Client $client, Invoice $invoice) public function __construct(Client $client, Invoice $invoice)
{ {
$this->client = $client; $this->client = $client;
@ -39,11 +42,13 @@ class ApplyNumber extends AbstractService
switch ($this->client->getSetting('counter_number_applied')) { switch ($this->client->getSetting('counter_number_applied')) {
case 'when_saved': case 'when_saved':
$this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id); $this->trySaving();
// $this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id);
break; break;
case 'when_sent': case 'when_sent':
if ($this->invoice->status_id == Invoice::STATUS_SENT) { if ($this->invoice->status_id == Invoice::STATUS_SENT) {
$this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id); $this->trySaving();
// $this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id);
} }
break; break;
@ -53,4 +58,33 @@ class ApplyNumber extends AbstractService
return $this->invoice; return $this->invoice;
} }
private function trySaving()
{
$x=1;
do{
try{
$this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id);
$this->invoice->saveQuietly();
$this->completed = false;
}
catch(QueryException $e){
$x++;
if($x>10)
$this->completed = false;
}
}
while($this->completed);
}
} }

View File

@ -15,6 +15,7 @@ use App\Models\Client;
use App\Models\Invoice; use App\Models\Invoice;
use App\Services\AbstractService; use App\Services\AbstractService;
use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\GeneratesCounter;
use Illuminate\Database\QueryException;
class ApplyRecurringNumber extends AbstractService class ApplyRecurringNumber extends AbstractService
{ {
@ -24,6 +25,8 @@ class ApplyRecurringNumber extends AbstractService
private $invoice; private $invoice;
private bool $completed = true;
public function __construct(Client $client, Invoice $invoice) public function __construct(Client $client, Invoice $invoice)
{ {
$this->client = $client; $this->client = $client;
@ -39,11 +42,13 @@ class ApplyRecurringNumber extends AbstractService
switch ($this->client->getSetting('counter_number_applied')) { switch ($this->client->getSetting('counter_number_applied')) {
case 'when_saved': case 'when_saved':
$this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client, $this->invoice); $this->trySaving();
//$this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client, $this->invoice);
break; break;
case 'when_sent': case 'when_sent':
if ($this->invoice->status_id == Invoice::STATUS_SENT) { if ($this->invoice->status_id == Invoice::STATUS_SENT) {
$this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client, $this->invoice); $this->trySaving();
// $this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client, $this->invoice);
} }
break; break;
@ -54,4 +59,33 @@ class ApplyRecurringNumber extends AbstractService
return $this->invoice; return $this->invoice;
} }
private function trySaving()
{
$x=1;
do{
try{
$this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client, $this->invoice);
$this->invoice->saveQuietly();
$this->completed = false;
}
catch(QueryException $e){
$x++;
if($x>10)
$this->completed = false;
}
}
while($this->completed);
}
} }

View File

@ -14,6 +14,7 @@ namespace App\Services\Payment;
use App\Models\Payment; use App\Models\Payment;
use App\Services\AbstractService; use App\Services\AbstractService;
use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\GeneratesCounter;
use Illuminate\Database\QueryException;
class ApplyNumber extends AbstractService class ApplyNumber extends AbstractService
{ {
@ -21,6 +22,8 @@ class ApplyNumber extends AbstractService
private $payment; private $payment;
private bool $completed = true;
public function __construct(Payment $payment) public function __construct(Payment $payment)
{ {
$this->client = $payment->client; $this->client = $payment->client;
@ -34,8 +37,38 @@ class ApplyNumber extends AbstractService
return $this->payment; return $this->payment;
} }
$this->payment->number = $this->getNextPaymentNumber($this->client, $this->payment); $this->trySaving();
// $this->payment->number = $this->getNextPaymentNumber($this->client, $this->payment);
return $this->payment; return $this->payment;
} }
private function trySaving()
{
$x=1;
do{
try{
$this->payment->number = $this->getNextPaymentNumber($this->client, $this->payment);
$this->payment->saveQuietly();
$this->completed = false;
}
catch(QueryException $e){
$x++;
if($x>10)
$this->completed = false;
}
}
while($this->completed);
}
} }

View File

@ -13,6 +13,7 @@ namespace App\Services\Quote;
use App\Models\Quote; use App\Models\Quote;
use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\GeneratesCounter;
use Illuminate\Database\QueryException;
class ApplyNumber class ApplyNumber
{ {
@ -20,6 +21,8 @@ class ApplyNumber
private $client; private $client;
private bool $completed = true;
public function __construct($client) public function __construct($client)
{ {
$this->client = $client; $this->client = $client;
@ -33,11 +36,13 @@ class ApplyNumber
switch ($this->client->getSetting('counter_number_applied')) { switch ($this->client->getSetting('counter_number_applied')) {
case 'when_saved': case 'when_saved':
$quote->number = $this->getNextQuoteNumber($this->client, $quote); $quote = $this->trySaving($quote);
// $quote->number = $this->getNextQuoteNumber($this->client, $quote);
break; break;
case 'when_sent': case 'when_sent':
if ($quote->status_id == Quote::STATUS_SENT) { if ($quote->status_id == Quote::STATUS_SENT) {
$quote->number = $this->getNextQuoteNumber($this->client, $quote); $quote = $this->trySaving($quote);
// $quote->number = $this->getNextQuoteNumber($this->client, $quote);
} }
break; break;
@ -48,4 +53,34 @@ class ApplyNumber
return $quote; return $quote;
} }
private function trySaving($quote)
{
$x=1;
do{
try{
$quote->number = $this->getNextQuoteNumber($this->client, $quote);
$quote->saveQuietly();
$this->completed = false;
}
catch(QueryException $e){
$x++;
if($x>10)
$this->completed = false;
}
}
while($this->completed);
return $quote;
}
} }

View File

@ -14,6 +14,7 @@ namespace App\Services\Recurring;
use App\Models\Client; use App\Models\Client;
use App\Services\AbstractService; use App\Services\AbstractService;
use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\GeneratesCounter;
use Illuminate\Database\QueryException;
class ApplyNumber extends AbstractService class ApplyNumber extends AbstractService
{ {
@ -23,6 +24,8 @@ class ApplyNumber extends AbstractService
private $recurring_entity; private $recurring_entity;
private bool $completed = true;
public function __construct(Client $client, $recurring_entity) public function __construct(Client $client, $recurring_entity)
{ {
$this->client = $client; $this->client = $client;
@ -36,8 +39,38 @@ class ApplyNumber extends AbstractService
if ($this->recurring_entity->number != '') if ($this->recurring_entity->number != '')
return $this->recurring_entity; return $this->recurring_entity;
$this->recurring_entity->number = $this->getNextRecurringInvoiceNumber($this->client, $this->recurring_entity); $this->trySaving();
//$this->recurring_entity->number = $this->getNextRecurringInvoiceNumber($this->client, $this->recurring_entity);
return $this->recurring_entity; return $this->recurring_entity;
} }
private function trySaving()
{
$x=1;
do{
try{
$this->recurring_entity->number = $this->getNextRecurringInvoiceNumber($this->client, $this->recurring_entity);
$this->recurring_entity->saveQuietly();
$this->completed = false;
}
catch(QueryException $e){
$x++;
if($x>10)
$this->completed = false;
}
}
while($this->completed);
}
} }