1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-09 12:42:36 +01:00

Added per client invoice counter #1344

This commit is contained in:
Hillel Coren 2017-03-29 11:46:52 +03:00
parent d292fc2786
commit cc63385e14
15 changed files with 132 additions and 37 deletions

View File

@ -49,6 +49,8 @@ class Client extends EntityModel
'language_id',
'payment_terms',
'website',
'invoice_number_counter',
'quote_number_counter',
];
/**

View File

@ -64,9 +64,11 @@ class Invoice extends EntityModel implements BalanceAffecting
*/
public static $patternFields = [
'counter',
'custom1',
'custom2',
'idNumber',
'clientInvoiceCounter',
'clientQuoteCounter',
'clientCustom1',
'clientCustom2',
'clientIdNumber',
'userId',
'year',
'date:',

View File

@ -125,7 +125,7 @@ trait GeneratesNumbers
{
$pattern = $invoice->invoice_type_id == INVOICE_TYPE_QUOTE ? $this->quote_number_pattern : $this->invoice_number_pattern;
return strstr($pattern, '$custom') || strstr($pattern, '$idNumber');
return strstr($pattern, '$client') !== false || strstr($pattern, '$idNumber') !== false;
}
/**
@ -161,16 +161,12 @@ trait GeneratesNumbers
if (count($matches) > 1) {
$format = $matches[1];
$search[] = $matches[0];
//$date = date_create()->format($format);
$date = Carbon::now(session(SESSION_TIMEZONE, DEFAULT_TIMEZONE))->format($format);
$replace[] = str_replace($format, $date, $matches[1]);
}
$pattern = str_replace($search, $replace, $pattern);
if ($entity->client_id) {
$pattern = $this->getClientInvoiceNumber($pattern, $entity);
}
$pattern = $this->getClientInvoiceNumber($pattern, $entity);
return $pattern;
}
@ -183,7 +179,7 @@ trait GeneratesNumbers
*/
private function getClientInvoiceNumber($pattern, $invoice)
{
if (! $invoice->client) {
if (! $invoice->client_id) {
return $pattern;
}
@ -191,12 +187,22 @@ trait GeneratesNumbers
'{$custom1}',
'{$custom2}',
'{$idNumber}',
'{$clientCustom1}',
'{$clientCustom2}',
'{$clientIdNumber}',
'{$clientInvoiceCounter}',
'{$clientQuoteCounter}',
];
$replace = [
$invoice->client->custom_value1,
$invoice->client->custom_value2,
$invoice->client->id_number,
$invoice->client->custom_value1, // backwards compatibility
$invoice->client->custom_value2,
$invoice->client->id_number,
str_pad($invoice->client->invoice_number_counter, $this->invoice_number_padding, '0', STR_PAD_LEFT),
str_pad($invoice->client->quote_number_counter, $this->invoice_number_padding, '0', STR_PAD_LEFT),
];
return str_replace($search, $replace, $pattern);
@ -225,7 +231,9 @@ trait GeneratesNumbers
*/
public function previewNextInvoiceNumber($entityType = ENTITY_INVOICE)
{
$invoice = $this->createInvoice($entityType);
$client = \App\Models\Client::scope()->first();
$invoice = $this->createInvoice($entityType, $client ? $client->id : 0);
return $this->getNextNumber($invoice);
}
@ -239,13 +247,41 @@ trait GeneratesNumbers
if ($this->client_number_counter) {
$this->client_number_counter += 1;
}
} elseif ($entity->isType(INVOICE_TYPE_QUOTE) && ! $this->share_counter) {
$this->quote_number_counter += 1;
} else {
$this->invoice_number_counter += 1;
$this->save();
return;
}
$this->save();
if ($this->usesClientInvoiceCounter()) {
$entity->client->invoice_number_counter += 1;
$entity->client->save();
} elseif ($this->usesClientQuoteCounter()) {
$entity->client->quote_number_counter += 1;
$entity->client->save();
}
if ($this->usesInvoiceCounter()) {
if ($entity->isType(INVOICE_TYPE_QUOTE) && ! $this->share_counter) {
$this->quote_number_counter += 1;
} else {
$this->invoice_number_counter += 1;
}
$this->save();
}
}
public function usesInvoiceCounter()
{
return strpos($this->invoice_number_pattern, '{$counter}') !== false;
}
public function usesClientInvoiceCounter()
{
return strpos($this->invoice_number_pattern, '{$clientInvoiceCounter}') !== false;
}
public function usesClientQuoteCounter()
{
return strpos($this->invoice_number_pattern, '{$clientQuoteCounter}') !== false;
}
public function clientNumbersEnabled()

View File

@ -131,6 +131,8 @@ class ClientTransformer extends EntityTransformer
'currency_id' => (int) $client->currency_id,
'custom_value1' => $client->custom_value1,
'custom_value2' => $client->custom_value2,
'invoice_number_counter' => (int) $client->invoice_number_counter,
'quote_number_counter' => (int) $client->quote_number_counter,
]);
}
}

View File

@ -175,7 +175,15 @@ class AppServiceProvider extends ServiceProvider
});
Validator::extend('has_counter', function ($attribute, $value, $parameters) {
return ! $value || strstr($value, '{$counter}');
if (! $value) {
return true;
}
if (strstr($value, '{$counter}') !== false) {
return true;
}
return ((strstr($value, '{$idNumber}') !== false || strstr($value, '{$clientIdNumber}') != false) && (strstr($value, '{$clientInvoiceCounter}') || strstr($value, '{$clientQuoteCounter}')));
});
Validator::extend('valid_invoice_items', function ($attribute, $value, $parameters) {

View File

@ -19,6 +19,11 @@ class AddGatewayFeeLocation extends Migration
$table->date('reset_counter_date')->nullable();
});
Schema::table('clients', function ($table) {
$table->integer('invoice_number_counter')->default(1)->nullable();
$table->integer('quote_number_counter')->default(1)->nullable();
});
// update invoice_item_type_id for task invoice items
DB::statement('update invoice_items
left join invoices on invoices.id = invoice_items.invoice_id
@ -37,5 +42,10 @@ class AddGatewayFeeLocation extends Migration
$table->dropColumn('gateway_fee_enabled');
$table->dropColumn('reset_counter_date');
});
Schema::table('clients', function ($table) {
$table->dropColumn('invoice_number_counter');
$table->dropColumn('quote_number_counter');
});
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1151,3 +1151,10 @@ function firstJSONError(json) {
}
return false;
}
// http://stackoverflow.com/questions/10073699/pad-a-number-with-leading-zeros-in-javascript
function pad(n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}

View File

@ -732,7 +732,7 @@ $LANG = array(
'recurring_hour' => 'Recurring Hour',
'pattern' => 'Pattern',
'pattern_help_title' => 'Pattern Help',
'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
'pattern_help_1' => 'Create custom numbers by specifying a pattern',
'pattern_help_2' => 'Available variables:',
'pattern_help_3' => 'For example, :example would be converted to :value',
'see_options' => 'See options',

View File

@ -73,7 +73,7 @@ return array(
"has_credit" => "The client does not have enough credit.",
"notmasked" => "The values are masked",
"less_than" => "The :attribute must be less than :value",
"has_counter" => "The value must contain {\$counter}",
"has_counter" => "To enusre all invoice numbers are unique the pattern needs to contain either {\$counter} or {\$clientIdNumber} and {\$clientInvoiceCounter}",
"valid_contacts" => "The contact must have either an email or name",
"valid_invoice_items" => "The invoice exceeds the maximum amount",
"valid_subdomain" => "The subdomain is restricted",

View File

@ -132,7 +132,7 @@
{!! Former::text('client_number_pattern')
->appendIcon('question-sign')
->addGroupClass('client-pattern')
->addGroupClass('number-pattern')
->addGroupClass('client-number-pattern')
->label(trans('texts.pattern')) !!}
{!! Former::text('client_number_counter')
->label(trans('texts.counter'))
@ -352,12 +352,14 @@
@foreach (\App\Models\Invoice::$patternFields as $field)
@if ($field == 'date:')
<li>{$date:format} - {!! link_to(PHP_DATE_FORMATS, trans('texts.see_options'), ['target' => '_blank']) !!}</li>
@elseif (strpos($field, 'client') !== false)
<li class="hide-client">{${{ $field }}}</li>
@else
<li>{${{ $field }}}</li>
@endif
@endforeach
</ul>
<p>{{ trans('texts.pattern_help_3', [
<p class="hide-client">{{ trans('texts.pattern_help_3', [
'example' => '{$year}-{$counter}',
'value' => date('Y') . '-0001'
]) }}</p>
@ -439,6 +441,12 @@
}
$('.number-pattern .input-group-addon').click(function() {
$('.hide-client').show();
$('#patternHelpModal').modal('show');
});
$('.client-number-pattern .input-group-addon').click(function() {
$('.hide-client').hide();
$('#patternHelpModal').modal('show');
});

View File

@ -24,8 +24,12 @@
@if ($client)
{!! Former::populate($client) !!}
{!! Former::hidden('public_id') !!}
@elseif ($account->client_number_counter)
{!! Former::populateField('id_number', $account->getNextNumber()) !!}
@else
{!! Former::populateField('invoice_number_counter', 1) !!}
{!! Former::populateField('quote_number_counter', 1) !!}
@if ($account->client_number_counter)
{!! Former::populateField('id_number', $account->getNextNumber()) !!}
@endif
@endif
<div class="row">
@ -52,8 +56,16 @@
{!! Former::text('custom_value2')->label($customLabel2) !!}
@endif
@endif
@if ($account->usesClientInvoiceCounter())
{!! Former::text('invoice_number_counter')->label('invoice_counter') !!}
@endif
@if ($account->usesClientQuoteCounter())
{!! Former::text('quote_number_counter')->label('quote_counter') !!}
@endif
</div>
</div>
</div>
<div class="panel panel-default" style="min-height: 500px">
<div class="panel-heading">

View File

@ -1622,11 +1622,17 @@
}
function setInvoiceNumber(client) {
@if ($invoice->id || !$account->hasClientNumberPattern($invoice))
@if ($invoice->id || !$account->hasClientNumberPattern($invoice))
return;
@endif
var number = '{{ $account->applyNumberPattern($invoice) }}';
number = number.replace('{$custom1}', client.custom_value1 ? client.custom_value1 : '');
number = number.replace('{$clientCustom1}', client.custom_value1 ? client.custom_value1 : '');
number = number.replace('{$clientCustom2}', client.custom_value2 ? client.custom_value1 : '');
number = number.replace('{$clientIdNumber}', client.id_number ? client.id_number : '');
number = number.replace('{$clientInvoiceCounter}', pad(client.invoice_number_counter, {{ $account->invoice_number_padding }}));
number = number.replace('{$clientQuoteCounter}', pad(client.quote_number_counter, {{ $account->invoice_number_padding }}));
// backwards compatibility
number = number.replace('{$custom1}', client.custom_value1 ? client.custom_value1 : '');
number = number.replace('{$custom2}', client.custom_value2 ? client.custom_value1 : '');
number = number.replace('{$idNumber}', client.id_number ? client.id_number : '');
model.invoice().invoice_number(number);