Separate counter for credit invoices #1451

This commit is contained in:
Hillel Coren 2017-06-27 22:07:10 +03:00
parent e217718918
commit 4d8fba0d70
11 changed files with 150 additions and 55 deletions

View File

@ -915,6 +915,9 @@ class AccountController extends BaseController
$account->client_number_prefix = trim(Input::get('client_number_prefix'));
$account->client_number_pattern = trim(Input::get('client_number_pattern'));
$account->client_number_counter = Input::get('client_number_counter');
$account->credit_number_counter = Input::get('credit_number_counter');
$account->credit_number_prefix = trim(Input::get('credit_number_prefix'));
$account->credit_number_pattern = trim(Input::get('credit_number_pattern'));
$account->reset_counter_frequency_id = Input::get('reset_counter_frequency_id');
$account->reset_counter_date = $account->reset_counter_frequency_id ? Utils::toSqlDate(Input::get('reset_counter_date')) : null;

View File

@ -57,6 +57,7 @@ class PurgeAccountData extends Job
$account->invoice_number_counter = 1;
$account->quote_number_counter = 1;
$account->credit_number_counter = 1;
$account->client_number_counter = $account->client_number_counter > 0 ? 1 : 0;
$account->save();

View File

@ -171,6 +171,9 @@ class Account extends Eloquent
'custom_contact_label2',
'domain_id',
'analytics_key',
'credit_number_counter',
'credit_number_prefix',
'credit_number_pattern',
];
/**

View File

@ -10,6 +10,7 @@ use App\Events\InvoiceInvitationWasEmailed;
use App\Events\QuoteInvitationWasEmailed;
use App\Libraries\CurlUtils;
use App\Models\Activity;
use App\Models\Credit;
use App\Models\Traits\ChargesFees;
use App\Models\Traits\HasRecurrence;
use DateTime;
@ -1405,8 +1406,13 @@ class Invoice extends EntityModel implements BalanceAffecting
}
Invoice::creating(function ($invoice) {
if (! $invoice->is_recurring && $invoice->amount >= 0) {
$invoice->account->incrementCounter($invoice);
if (! $invoice->is_recurring) {
$account = $invoice->account;
if ($invoice->amount >= 0) {
$account->incrementCounter($invoice);
} elseif ($account->credit_number_counter > 0) {
$account->incrementCounter(new Credit());
}
}
});

View File

@ -67,6 +67,11 @@ trait GeneratesNumbers
$this->client_number_counter += $counterOffset - 1;
$this->save();
}
} elseif ($entity->isEntityType(ENTITY_CREDIT)) {
if ($this->creditNumbersEnabled()) {
$this->credit_number_counter += $counterOffset - 1;
$this->save();
}
} elseif ($entity->isType(INVOICE_TYPE_QUOTE)) {
if (! $this->share_counter) {
$this->quote_number_counter += $counterOffset - 1;
@ -227,6 +232,8 @@ trait GeneratesNumbers
{
if ($entityType == ENTITY_CLIENT) {
return $this->client_number_counter;
} elseif ($entityType == ENTITY_CREDIT) {
return $this->credit_number_counter;
} elseif ($entityType == ENTITY_QUOTE && ! $this->share_counter) {
return $this->quote_number_counter;
} else {
@ -254,11 +261,17 @@ trait GeneratesNumbers
public function incrementCounter($entity)
{
if ($entity->isEntityType(ENTITY_CLIENT)) {
if ($this->client_number_counter) {
if ($this->client_number_counter > 0) {
$this->client_number_counter += 1;
}
$this->save();
return;
} elseif ($entity->isEntityType(ENTITY_CREDIT)) {
if ($this->credit_number_counter > 0) {
$this->credit_number_counter += 1;
}
$this->save();
return;
}
if ($this->usesClientInvoiceCounter()) {
@ -295,6 +308,11 @@ trait GeneratesNumbers
return $this->hasFeature(FEATURE_INVOICE_SETTINGS) && $this->client_number_counter > 0;
}
public function creditNumbersEnabled()
{
return $this->hasFeature(FEATURE_INVOICE_SETTINGS) && $this->credit_number_counter > 0;
}
public function checkCounterReset()
{
if (! $this->reset_counter_frequency_id || ! $this->reset_counter_date) {

View File

@ -16,6 +16,12 @@ class UpdateDarkMode extends Migration
$table->boolean('dark_mode')->default(true)->change();
});
Schema::table('accounts', function ($table) {
$table->integer('credit_number_counter')->default(0)->nullable();
$table->text('credit_number_prefix')->nullable();
$table->text('credit_number_pattern')->nullable();
});
DB::statement('update users set dark_mode = 1;');
// update invoice_item_type_id for task invoice items
@ -82,5 +88,11 @@ class UpdateDarkMode extends Migration
Schema::table('expenses', function ($table) {
$table->dropColumn('recurring_expense_id');
});
Schema::table('accounts', function ($table) {
$table->dropColumn('credit_number_counter');
$table->dropColumn('credit_number_prefix');
$table->dropColumn('credit_number_pattern');
});
}
}

File diff suppressed because one or more lines are too long

View File

@ -2290,6 +2290,12 @@ $LANG = array(
'view_recurring_expense' => 'View Recurring Expense',
'other' => 'Other',
'import_failed' => 'Import Failed',
'recurring_prefix' => 'Recurring Prefix',
'options' => 'Options',
'credit_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the credit number for negative invoices.',
'next_credit_number' => 'The next credit number is :number.',
'padding_help' => 'The number of zero\'s to pad the number.',
'client_number_help'
);

View File

@ -45,10 +45,10 @@
<a href="#client_number" aria-controls="client_number" role="tab" data-toggle="tab">{{ trans('texts.client_number') }}</a>
</li>
<li role="presentation">
<a href="#recurring_invoice_number" aria-controls="recurring_invoice_number" role="tab" data-toggle="tab">{{ trans('texts.recurring_invoice_number') }}</a>
<a href="#credit_number" aria-controls="credit_number" role="tab" data-toggle="tab">{{ trans('texts.credit_number') }}</a>
</li>
<li role="presentation">
<a href="#reset_counter" aria-controls="reset_counter" role="tab" data-toggle="tab">{{ trans('texts.reset_counter') }}</a>
<a href="#options" aria-controls="options" role="tab" data-toggle="tab">{{ trans('texts.options') }}</a>
</li>
</ul>
</div>
@ -56,7 +56,7 @@
<div role="tabpanel" class="tab-pane active" id="invoice_number">
<div class="panel-body">
{!! Former::inline_radios('invoice_number_type')
->onchange('onInvoiceNumberTypeChange()')
->onchange("onNumberTypeChange('invoice')")
->label(trans('texts.type'))
->radios([
trans('texts.prefix') => ['value' => 'prefix', 'name' => 'invoice_number_type'],
@ -71,7 +71,6 @@
->addGroupClass('invoice-pattern')
->label(trans('texts.pattern'))
->addGroupClass('number-pattern') !!}
{!! Former::text('invoice_number_padding') !!}
{!! Former::text('invoice_number_counter')
->label(trans('texts.counter'))
->help(trans('texts.invoice_number_help') . ' ' .
@ -81,7 +80,7 @@
<div role="tabpanel" class="tab-pane" id="quote_number">
<div class="panel-body">
{!! Former::inline_radios('quote_number_type')
->onchange('onQuoteNumberTypeChange()')
->onchange("onNumberTypeChange('quote')")
->label(trans('texts.type'))
->radios([
trans('texts.prefix') => ['value' => 'prefix', 'name' => 'quote_number_type'],
@ -119,7 +118,7 @@
<div id="clientNumberDiv" style="display:none">
{!! Former::inline_radios('client_number_type')
->onchange('onClientNumberTypeChange()')
->onchange("onNumberTypeChange('client')")
->label(trans('texts.type'))
->radios([
trans('texts.prefix') => ['value' => 'prefix', 'name' => 'client_number_type'],
@ -143,21 +142,55 @@
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="recurring_invoice_number">
<div role="tabpanel" class="tab-pane" id="credit_number">
<div class="panel-body">
{!! Former::checkbox('credit_number_enabled')
->label('credit_number')
->onchange('onCreditNumberEnabled()')
->text('enable')
->value(1)
->check($account->credit_number_counter > 0) !!}
<div id="creditNumberDiv" style="display:none">
{!! Former::inline_radios('credit_number_type')
->onchange("onNumberTypeChange('credit')")
->label(trans('texts.type'))
->radios([
trans('texts.prefix') => ['value' => 'prefix', 'name' => 'credit_number_type'],
trans('texts.pattern') => ['value' => 'pattern', 'name' => 'credit_number_type'],
])->check($account->credit_number_pattern ? 'pattern' : 'prefix') !!}
{!! Former::text('credit_number_prefix')
->addGroupClass('credit-prefix')
->label(trans('texts.prefix')) !!}
{!! Former::text('credit_number_pattern')
->appendIcon('question-sign')
->addGroupClass('credit-pattern')
->addGroupClass('credit-number-pattern')
->label(trans('texts.pattern')) !!}
{!! Former::text('credit_number_counter')
->label(trans('texts.counter'))
->addGroupClass('pad-checkbox')
->help(trans('texts.credit_number_help') . ' ' .
trans('texts.next_credit_number', ['number' => $account->getNextNumber(new \App\Models\Credit()) ?: '0001'])) !!}
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="options">
<div class="panel-body">
{!! Former::text('invoice_number_padding')
->help('padding_help') !!}
{!! Former::text('recurring_invoice_number_prefix')
->label(trans('texts.prefix'))
->label(trans('texts.recurring_prefix'))
->help(trans('texts.recurring_invoice_number_prefix_help')) !!}
</div>
</div>
<div role="tabpanel" class="tab-pane" id="reset_counter">
<div class="panel-body">
{!! Former::select('reset_counter_frequency_id')
->onchange('onResetFrequencyChange()')
->label('frequency')
->label('reset_counter')
->addOption(trans('texts.never'), '')
->options(\App\Models\Frequency::selectOptions())
->help('reset_counter_help') !!}
@ -393,36 +426,14 @@
$('#quote_number_counter').val(disabled ? '' : '{!! $account->quote_number_counter !!}');
}
function onInvoiceNumberTypeChange() {
var val = $('input[name=invoice_number_type]:checked').val()
function onNumberTypeChange(entityType) {
var val = $('input[name=' + entityType + '_number_type]:checked').val();
if (val == 'prefix') {
$('.invoice-prefix').show();
$('.invoice-pattern').hide();
$('.' + entityType + '-prefix').show();
$('.' + entityType + '-pattern').hide();
} else {
$('.invoice-prefix').hide();
$('.invoice-pattern').show();
}
}
function onQuoteNumberTypeChange() {
var val = $('input[name=quote_number_type]:checked').val()
if (val == 'prefix') {
$('.quote-prefix').show();
$('.quote-pattern').hide();
} else {
$('.quote-prefix').hide();
$('.quote-pattern').show();
}
}
function onClientNumberTypeChange() {
var val = $('input[name=client_number_type]:checked').val()
if (val == 'prefix') {
$('.client-prefix').show();
$('.client-pattern').hide();
} else {
$('.client-prefix').hide();
$('.client-pattern').show();
$('.' + entityType + '-prefix').hide();
$('.' + entityType + '-pattern').show();
}
}
@ -437,6 +448,17 @@
}
}
function onCreditNumberEnabled() {
var enabled = $('#credit_number_enabled').is(':checked');
if (enabled) {
$('#creditNumberDiv').show();
$('#credit_number_counter').val({{ $account->credit_number_counter ?: 1 }});
} else {
$('#creditNumberDiv').hide();
$('#credit_number_counter').val(0);
}
}
function onResetFrequencyChange() {
var val = $('#reset_counter_frequency_id').val();
if (val) {
@ -456,12 +478,20 @@
$('#patternHelpModal').modal('show');
});
$('.credit-number-pattern .input-group-addon').click(function() {
$('.hide-client').hide();
$('#patternHelpModal').modal('show');
});
$(function() {
setQuoteNumberEnabled();
onInvoiceNumberTypeChange();
onQuoteNumberTypeChange();
onClientNumberTypeChange();
onNumberTypeChange('invoice');
onNumberTypeChange('quote');
onNumberTypeChange('client');
onNumberTypeChange('credit');
onClientNumberEnabled();
onCreditNumberEnabled();
onResetFrequencyChange();
$('#reset_counter_date').datepicker('update', '{{ Utils::fromSqlDate($account->reset_counter_date) ?: 'new Date()' }}');

View File

@ -159,7 +159,7 @@
{!! Former::text('invoice_date')->data_bind("datePicker: invoice_date, valueUpdate: 'afterkeydown'")->label(trans("texts.{$entityType}_date"))
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->appendIcon('calendar')->addGroupClass('invoice_date') !!}
{!! Former::text('due_date')->data_bind("datePicker: due_date, valueUpdate: 'afterkeydown'")->label($account->getLabel($invoice->getDueDateLabel()))
->placeholder($invoice->exists || $invoice->isQuote() ? ' ' : $account->present()->dueDatePlaceholder())
->placeholder($invoice->id || $invoice->isQuote() ? ' ' : $account->present()->dueDatePlaceholder())
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->appendIcon('calendar')->addGroupClass('due_date') !!}
{!! Former::text('partial')->data_bind("value: partial, valueUpdate: 'afterkeydown'")->onkeyup('onPartialChange()')
->addGroupClass('partial')!!}
@ -482,7 +482,7 @@
{!! Former::select('invoice_design_id')->style('display:inline;width:150px;background-color:white !important')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id") !!}
@endif
@if ( $invoice->exists && $invoice->id && ! $invoice->is_recurring)
@if ( $invoice->id && ! $invoice->is_recurring)
{!! Button::primary(trans('texts.download_pdf'))
->withAttributes(['onclick' => 'onDownloadClick()', 'id' => 'downloadPdfButton'])
->appendIcon(Icon::create('download-alt')) !!}
@ -1155,7 +1155,20 @@
return invoice;
}
var origInvoiceNumber = false;
function getPDFString(cb, force) {
@if (! $invoice->id && $account->credit_number_counter > 0)
var total = model.invoice().totals.rawTotal();
var invoiceNumber = model.invoice().invoice_number();
var creditNumber = "{{ $account->getNextNumber(new \App\Models\Credit()) }}";
if (total < 0 && invoiceNumber != creditNumber) {
origInvoiceNumber = invoiceNumber;
model.invoice().invoice_number(creditNumber);
} else if (total >= 0 && invoiceNumber == creditNumber && origInvoiceNumber) {
model.invoice().invoice_number(origInvoiceNumber);
}
@endif
@if ( ! $account->live_preview)
return;
@endif

View File

@ -35,7 +35,7 @@ function ViewModel(data) {
dueDate = moment(dueDate).format("{{ $account->getMomentDateFormat() }}");
$('#due_date').attr('placeholder', dueDate);
} else {
$('#due_date').attr('placeholder', "{{ $invoice->exists || $invoice->isQuote() ? ' ' : $account->present()->dueDatePlaceholder() }}");
$('#due_date').attr('placeholder', "{{ $invoice->id || $invoice->isQuote() ? ' ' : $account->present()->dueDatePlaceholder() }}");
}
@endif
}
@ -1007,7 +1007,7 @@ ko.bindingHandlers.productTypeahead = {
};
function checkInvoiceNumber() {
var url = '{{ url('check_invoice_number') }}/{{ $invoice->exists ? $invoice->public_id : '' }}?invoice_number=' + encodeURIComponent($('#invoice_number').val());
var url = '{{ url('check_invoice_number') }}/{{ $invoice->id ? $invoice->public_id : '' }}?invoice_number=' + encodeURIComponent($('#invoice_number').val());
$.get(url, function(data) {
var isValid = data == '{{ RESULT_SUCCESS }}' ? true : false;
if (isValid) {