Bug fixes

This commit is contained in:
Hillel Coren 2015-05-09 21:25:16 +03:00
parent 9198677277
commit f41e0d999b
32 changed files with 204 additions and 93 deletions

View File

@ -10,6 +10,8 @@ use Input;
use Utils; use Utils;
use View; use View;
use Session; use Session;
use Cookie;
use Response;
use App\Models\User; use App\Models\User;
use App\Ninja\Mailers\Mailer; use App\Ninja\Mailers\Mailer;
use App\Ninja\Repositories\AccountRepository; use App\Ninja\Repositories\AccountRepository;
@ -34,7 +36,15 @@ class AppController extends BaseController
return Redirect::to('/'); return Redirect::to('/');
} }
return View::make('setup'); $view = View::make('setup');
/*
$cookie = Cookie::forget('ninja_session', '/', 'www.ninja.dev');
Cookie::queue($cookie);
return Response::make($view)->withCookie($cookie);
*/
return Response::make($view);
} }
public function doSetup() public function doSetup()

View File

@ -451,7 +451,7 @@ class InvoiceController extends BaseController
$pdfUpload = Input::get('pdfupload'); $pdfUpload = Input::get('pdfupload');
if (!empty($pdfUpload) && strpos($pdfUpload, 'data:application/pdf;base64,') === 0) { if (!empty($pdfUpload) && strpos($pdfUpload, 'data:application/pdf;base64,') === 0) {
$this->storePDF(Input::get('pdfupload'), $invoice->id); $this->storePDF(Input::get('pdfupload'), $invoice);
} }
if ($action == 'clone') { if ($action == 'clone') {
@ -597,11 +597,9 @@ class InvoiceController extends BaseController
return View::make('invoices.history', $data); return View::make('invoices.history', $data);
} }
private function storePDF($encodedString, $invoiceId) private function storePDF($encodedString, $invoice)
{ {
$uploadsDir = storage_path().'/pdfcache/';
$encodedString = str_replace('data:application/pdf;base64,', '', $encodedString); $encodedString = str_replace('data:application/pdf;base64,', '', $encodedString);
$name = 'cache-'.$invoiceId.'.pdf'; file_put_contents($invoice->getPDFPath(), base64_decode($encodedString));
file_put_contents($uploadsDir.$name, base64_decode($encodedString));
} }
} }

View File

@ -632,11 +632,6 @@ class PaymentController extends BaseController
$payment->transaction_reference = $ref; $payment->transaction_reference = $ref;
$payment->payment_date = date_create()->format('Y-m-d'); $payment->payment_date = date_create()->format('Y-m-d');
if ($invoice->partial) {
$invoice->partial = 0;
$invoice->save();
}
if ($payerId) { if ($payerId) {
$payment->payer_id = $payerId; $payment->payer_id = $payerId;
} }

View File

@ -17,7 +17,7 @@ class DuplicateSubmissionCheck
$lastPage = session(SESSION_LAST_REQUEST_PAGE); $lastPage = session(SESSION_LAST_REQUEST_PAGE);
$lastTime = session(SESSION_LAST_REQUEST_TIME); $lastTime = session(SESSION_LAST_REQUEST_TIME);
if ($lastPage == $path && (microtime(true) - $lastTime <= 1.5)) { if ($lastPage == $path && (microtime(true) - $lastTime <= 1)) {
return redirect('/')->with('warning', trans('texts.duplicate_post')); return redirect('/')->with('warning', trans('texts.duplicate_post'));
} }

View File

@ -69,7 +69,7 @@ post('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@postLoginWr
get('/logout', array('as' => 'logout', 'uses' => 'Auth\AuthController@getLogout')); get('/logout', array('as' => 'logout', 'uses' => 'Auth\AuthController@getLogout'));
get('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getEmail')); get('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getEmail'));
post('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postEmail')); post('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postEmail'));
get('/password/reset', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getReset')); get('/password/reset/{token}', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getReset'));
post('/password/reset', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postReset')); post('/password/reset', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postReset'));
get('/user/confirm/{code}', 'UserController@confirm'); get('/user/confirm/{code}', 'UserController@confirm');

View File

@ -214,7 +214,6 @@ class Activity extends Eloquent
if ($invoice->isPaid() && $invoice->balance > 0) { if ($invoice->isPaid() && $invoice->balance > 0) {
$invoice->invoice_status_id = INVOICE_STATUS_PARTIAL; $invoice->invoice_status_id = INVOICE_STATUS_PARTIAL;
$invoice->save();
} }
} }
} }
@ -292,7 +291,7 @@ class Activity extends Eloquent
$invoice = $payment->invoice; $invoice = $payment->invoice;
$invoice->balance = $invoice->balance - $payment->amount; $invoice->balance = $invoice->balance - $payment->amount;
$invoice->invoice_status_id = ($invoice->balance > 0) ? INVOICE_STATUS_PARTIAL : INVOICE_STATUS_PAID; $invoice->invoice_status_id = ($invoice->balance > 0) ? INVOICE_STATUS_PARTIAL : INVOICE_STATUS_PAID;
$invoice->partial = 0; $invoice->partial = max(0, $invoice->partial - $payment->amount);
$invoice->save(); $invoice->save();
} }

View File

@ -33,7 +33,7 @@ class Invitation extends EntityModel
$url = SITE_URL; $url = SITE_URL;
if ($this->account->subdomain) { if ($this->account->subdomain) {
$url = str_replace(['://www', '://'], "://{$this->account->subdomain}.", $url); $url = str_replace('://www.', "://{$this->account->subdomain}.", $url);
} }
return "{$url}/view/{$this->invitation_key}"; return "{$url}/view/{$this->invitation_key}";

View File

@ -57,6 +57,11 @@ class Invoice extends EntityModel
return trans("texts.$entityType") . '_' . $this->invoice_number . '.pdf'; return trans("texts.$entityType") . '_' . $this->invoice_number . '.pdf';
} }
public function getPDFPath()
{
return storage_path() . '/pdfcache/cache-' . $this->id . '.pdf';
}
public function getLink() public function getLink()
{ {
return link_to('invoices/'.$this->public_id, $this->invoice_number); return link_to('invoices/'.$this->public_id, $this->invoice_number);

View File

@ -22,11 +22,10 @@ class Mailer
} }
if(isset($data['invoice_id'])) { if(isset($data['invoice_id'])) {
$invoice = Invoice::scope()->with("account")->where('id', '=', $data['invoice_id'])->get()->first(); $invoice = Invoice::with('account')->where('id', '=', $data['invoice_id'])->get()->first();
$pdfPath = storage_path().'/pdfcache/cache-'.$invoice->id.'.pdf'; if($invoice->account->pdf_email_attachment && file_exists($invoice->getPDFPath())) {
if($invoice->account->pdf_email_attachment && file_exists($pdfPath)) {
$message->attach( $message->attach(
$pdfPath, $invoice->getPDFPath(),
array('as' => $invoice->getFileName(), 'mime' => 'application/pdf') array('as' => $invoice->getFileName(), 'mime' => 'application/pdf')
); );
} }

View File

@ -35,7 +35,7 @@ class AccountRepository
$user = new User(); $user = new User();
if (!$firstName && !$lastName && !$email && !$password) { if (!$firstName && !$lastName && !$email && !$password) {
$user->password = str_random(RANDOM_KEY_LENGTH); $user->password = str_random(RANDOM_KEY_LENGTH);
//$user->email = $user->username = str_random(RANDOM_KEY_LENGTH); $user->username = str_random(RANDOM_KEY_LENGTH);
} else { } else {
$user->first_name = $firstName; $user->first_name = $firstName;
$user->last_name = $lastName; $user->last_name = $lastName;

View File

@ -33090,6 +33090,83 @@ function roundToTwo(num, toString) {
function truncate(str, length) { function truncate(str, length) {
return (str && str.length > length) ? (str.substr(0, length-1) + '...') : str; return (str && str.length > length) ? (str.substr(0, length-1) + '...') : str;
} }
(function($)
{
/**
* Auto-growing textareas; technique ripped from Facebook
*
*
* http://github.com/jaz303/jquery-grab-bag/tree/master/javascripts/jquery.autogrow-textarea.js
*/
$.fn.autogrow = function(options)
{
return this.filter('textarea').each(function()
{
var self = this;
var $self = $(self);
var minHeight = $self.height();
var noFlickerPad = $self.hasClass('autogrow-short') ? 0 : parseInt($self.css('lineHeight')) || 0;
var settings = $.extend({
preGrowCallback: null,
postGrowCallback: null
}, options );
var shadow = $('<div></div>').css({
position: 'absolute',
top: -10000,
left: -10000,
width: $self.width(),
fontSize: $self.css('fontSize'),
fontFamily: $self.css('fontFamily'),
fontWeight: $self.css('fontWeight'),
lineHeight: $self.css('lineHeight'),
resize: 'none',
'word-wrap': 'break-word'
}).appendTo(document.body);
var update = function(event)
{
var times = function(string, number)
{
for (var i=0, r=''; i<number; i++) r += string;
return r;
};
var val = self.value.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/&/g, '&amp;')
.replace(/\n$/, '<br/>&nbsp;')
.replace(/\n/g, '<br/>')
.replace(/ {2,}/g, function(space){ return times('&nbsp;', space.length - 1) + ' ' });
// Did enter get pressed? Resize in this keydown event so that the flicker doesn't occur.
if (event && event.data && event.data.event === 'keydown' && event.keyCode === 13) {
val += '<br />';
}
shadow.css('width', $self.width());
shadow.html(val + (noFlickerPad === 0 ? '...' : '')); // Append '...' to resize pre-emptively.
var newHeight=Math.max(shadow.height() + noFlickerPad, minHeight);
if(settings.preGrowCallback!=null){
newHeight=settings.preGrowCallback($self,shadow,newHeight,minHeight);
}
$self.height(newHeight);
if(settings.postGrowCallback!=null){
settings.postGrowCallback($self);
}
}
$self.change(update).keyup(update).keydown({event:'keydown'},update);
$(window).resize(update);
update();
});
};
})(jQuery);
function GetPdfMake(invoice, javascript, callback) { function GetPdfMake(invoice, javascript, callback) {
var account = invoice.account; var account = invoice.account;
eval(javascript); eval(javascript);

View File

@ -16,12 +16,14 @@ Developed by [@hillelcoren](https://twitter.com/hillelcoren) | Designed by [kant
### Features ### Features
* Core application built using Laravel 5 * Built using Laravel 5
* Invoice PDF generation directly in the browser * Live PDF generation
* Integrates with many payment providers * Integrates with 30+ payment providers
* Recurring invoices * Recurring invoices
* Tax rates and payment terms * Tax rates and payment terms
* Multi-user support * Multi-user support
* Partial payments
* Custom email templates
* [Zapier](https://zapier.com/) integration * [Zapier](https://zapier.com/) integration
* [D3.js](http://d3js.org/) visualizations * [D3.js](http://d3js.org/) visualizations

View File

@ -73,6 +73,10 @@ return array(
"unique" => ":attribute er allerede taget.", "unique" => ":attribute er allerede taget.",
"url" => ":attribute formatet er ugyldigt.", "url" => ":attribute formatet er ugyldigt.",
"positive" => "The :attribute must be greater than zero.",
"has_credit" => "The client does not have enough credit.",
"notmasked" => "The values are masked",
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Custom Validation Language Lines | Custom Validation Language Lines

View File

@ -605,34 +605,6 @@ return array(
'app_title' => 'Free Open-Source Online Invoicing', 'app_title' => 'Free Open-Source Online Invoicing',
'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.', 'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.',
'plans' => [
'header' => '<span class="thin">The</span> Plans',
'free' => 'Free',
'unlimited' => 'Unlimited',
'pro_plan' => 'Pro Plan',
'go_pro' => 'Go Pro to Unlock Premium Invoice Ninja Features',
'go_pro_text' => 'We believe that the free version of Invoice Ninja is a truly awesome product loaded with the key features you need to bill your clients electronically. But for those who crave still more Ninja awesomeness, we\'ve unmasked the Invoice Ninja Pro plan, which offers more versatility, power and customization options for just $50 per year.',
'number_clients' => 'Number of clients per account',
'unlimited_invoices' => 'Unlimited client invoices',
'company_logo' => 'Add your company logo',
'live_pdf' => 'Live .PDF invoice creation',
'four_templates' => '4 beautiful invoice templates',
'payments' => 'Accept credit card payments',
'additional_templates' => 'Additional invoice templates',
'multi_user' => 'Multi-user support',
'quotes' => 'Quotes/pro-forma invoices',
'advanced_settings' => 'Advanced invoice settings',
'data_vizualizations' => 'Dynamic data vizualizations',
'email_support' => 'Priority email support',
'remove_created_by' => 'Remove "Created by Invoice Ninja"',
'latest_features' => 'Latest and greatest features',
'pricing' => 'Pricing',
'free_always' => 'Free<span> /Always!</span>',
'year_price' => '$50<span> /Year</span>',
],
'rows' => 'rows', 'rows' => 'rows',
'www' => 'www', 'www' => 'www',
'logo' => 'Logo', 'logo' => 'Logo',
@ -653,6 +625,4 @@ return array(
'recurring' => 'Recurring', 'recurring' => 'Recurring',
'last_invoice_sent' => 'Last invoice sent :date', 'last_invoice_sent' => 'Last invoice sent :date',
); );

View File

@ -72,9 +72,6 @@ return array(
"url" => "El formato :attribute es inválido.", "url" => "El formato :attribute es inválido.",
"positive" => ":attribute debe ser mayor que cero.", "positive" => ":attribute debe ser mayor que cero.",
"has_credit" => "el cliente no tiene crédito suficiente.", "has_credit" => "el cliente no tiene crédito suficiente.",
"positive" => "The :attribute must be greater than zero.",
"has_credit" => "The client does not have enough credit.",
"notmasked" => "The values are masked", "notmasked" => "The values are masked",

View File

@ -72,9 +72,6 @@ return array(
"url" => "El formato :attribute es inválido.", "url" => "El formato :attribute es inválido.",
"positive" => ":attribute debe ser mayor que cero.", "positive" => ":attribute debe ser mayor que cero.",
"has_credit" => "el cliente no tiene crédito suficiente.", "has_credit" => "el cliente no tiene crédito suficiente.",
"positive" => "The :attribute must be greater than zero.",
"has_credit" => "The client does not have enough credit.",
"notmasked" => "The values are masked", "notmasked" => "The values are masked",

View File

@ -73,9 +73,6 @@ return array(
"positive" => ":attribute moet groter zijn dan nul.", "positive" => ":attribute moet groter zijn dan nul.",
"has_credit" => "De klant heeft niet voldoende krediet.", "has_credit" => "De klant heeft niet voldoende krediet.",
"positive" => "The :attribute must be greater than zero.",
"has_credit" => "The client does not have enough credit.",
"notmasked" => "The values are masked", "notmasked" => "The values are masked",
/* /*

View File

@ -71,9 +71,6 @@ return array(
"positive" => ":attribute deve ser maior que zero.", "positive" => ":attribute deve ser maior que zero.",
"has_credit" => "O cliente não possui crédito suficiente.", "has_credit" => "O cliente não possui crédito suficiente.",
"positive" => "The :attribute must be greater than zero.",
"has_credit" => "The client does not have enough credit.",
"notmasked" => "The values are masked", "notmasked" => "The values are masked",

View File

@ -73,6 +73,10 @@ return [
"unique" => ":attribute används redan.", "unique" => ":attribute används redan.",
"url" => "Formatet :attribute är ogiltigt.", "url" => "Formatet :attribute är ogiltigt.",
"positive" => "The :attribute must be greater than zero.",
"has_credit" => "The client does not have enough credit.",
"notmasked" => "The values are masked",
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Custom Validation Language Lines | Custom Validation Language Lines

View File

@ -35,7 +35,7 @@
{!! Former::text('name') !!} {!! Former::text('name') !!}
@if (Auth::user()->isPro()) @if (Auth::user()->isPro() && !Utils::isNinja())
{{ Former::setOption('capitalize_translations', false) }} {{ Former::setOption('capitalize_translations', false) }}
{!! Former::text('subdomain')->placeholder('texts.www')->onchange('onSubdomainChange()') !!} {!! Former::text('subdomain')->placeholder('texts.www')->onchange('onSubdomainChange()') !!}
@endif @endif
@ -266,6 +266,7 @@
'&confirm_password=' + encodeURIComponent($('form #confirm_password').val()), '&confirm_password=' + encodeURIComponent($('form #confirm_password').val()),
success: function(result) { success: function(result) {
if (result == 'success') { if (result == 'success') {
NINJA.formIsChanged = false;
$('#changePasswordButton').hide(); $('#changePasswordButton').hide();
$('#successDiv').show(); $('#successDiv').show();
$('#cancelChangePasswordButton').html('{{ trans('texts.close') }}'); $('#cancelChangePasswordButton').html('{{ trans('texts.close') }}');
@ -289,5 +290,8 @@
</script> </script>
@stop
@section('onReady')
$('#name').focus();
@stop @stop

View File

@ -139,3 +139,7 @@
@stop @stop
@section('onReady')
$('#custom_invoice_label1').focus();
@stop

View File

@ -58,6 +58,10 @@
window.model = new ViewModel(); window.model = new ViewModel();
ko.applyBindings(model); ko.applyBindings(model);
$(function() {
$('#product_key').focus();
});
</script> </script>
@stop @stop

View File

@ -31,3 +31,7 @@
{!! Former::close() !!} {!! Former::close() !!}
@stop @stop
@section('onReady')
$('#name').focus();
@stop

View File

@ -114,7 +114,6 @@
{!! Former::close() !!} {!! Former::close() !!}
@if (!Utils::isNinja())
<p/> <p/>
<center> <center>
<!-- <!--
@ -141,8 +140,18 @@
<iframe allowTransparency="true" frameborder="0" scrolling="no" src="https://bitnami.com/product/invoice-ninja/widget" style="border:none;width:230px; height:100px;"></iframe> <iframe allowTransparency="true" frameborder="0" scrolling="no" src="https://bitnami.com/product/invoice-ninja/widget" style="border:none;width:230px; height:100px;"></iframe>
</center> </center>
@endif
</div> </div>
<script type="text/javascript">
$(function() {
if ($('#email').val()) {
$('#password').focus();
} else {
$('#email').focus();
}
})
</script>
@endsection @endsection

View File

@ -97,4 +97,10 @@
</div> </div>
</div> </div>
<script type="text/javascript">
$(function() {
$('#email').focus();
})
</script>
@stop @stop

View File

@ -102,4 +102,10 @@
</div> </div>
<script type="text/javascript">
$(function() {
$('#email').focus();
})
</script>
@stop @stop

View File

@ -1,10 +1,5 @@
@extends('header') @extends('header')
@section('onReady')
$('input#name').focus();
@stop
@section('content') @section('content')
@ -60,8 +55,18 @@
$('#currency_id').combobox(); $('#currency_id').combobox();
$('#credit_date').datepicker('update', new Date()); $('#credit_date').datepicker('update', new Date());
@if (!$clientPublicId)
$('.client-select input.form-control').focus();
@else
$('#amount').focus();
@endif
}); });
</script> </script>
@stop @stop
@section('onReady')
//$('.client-select input.form-control').focus();
@stop

View File

@ -30,9 +30,13 @@
{{ trans('texts.average_invoice') }} {{ trans('texts.average_invoice') }}
</div> </div>
<div class="in-bold"> <div class="in-bold">
@if (count($averageInvoice))
@foreach ($averageInvoice as $item) @foreach ($averageInvoice as $item)
{{ Utils::formatMoney($item->invoice_avg, $item->currency_id) }}<br/> {{ Utils::formatMoney($item->invoice_avg, $item->currency_id) }}<br/>
@endforeach @endforeach
@else
{{ Utils::formatMoney(0) }}
@endif
</div> </div>
</div> </div>
</div> </div>

View File

@ -366,7 +366,7 @@
<form class="navbar-form navbar-right" role="search"> <form class="navbar-form navbar-right" role="search">
<div class="form-group"> <div class="form-group">
<input type="text" id="search" style="width: 140px" <input type="text" id="search" style="width: {{ Session::get(SESSION_LOCALE) == 'en' ? 180 : 140 }}px"
class="form-control" placeholder="{{ trans('texts.search') }}"> class="form-control" placeholder="{{ trans('texts.search') }}">
</div> </div>
</form> </form>

View File

@ -169,7 +169,7 @@
->raw()->data_bind("value: product_key, valueUpdate: 'afterkeydown'")->addClass('datalist') !!} ->raw()->data_bind("value: product_key, valueUpdate: 'afterkeydown'")->addClass('datalist') !!}
</td> </td>
<td> <td>
<textarea data-bind="value: wrapped_notes, valueUpdate: 'afterkeydown'" rows="1" cols="60" style="resize: none;" class="form-control word-wrap"></textarea> <textarea data-bind="value: wrapped_notes, valueUpdate: 'afterkeydown'" rows="1" cols="60" style="resize: vertical" class="form-control word-wrap"></textarea>
</td> </td>
<td> <td>
<input onkeyup="onItemChange()" data-bind="value: prettyCost, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control"//> <input onkeyup="onItemChange()" data-bind="value: prettyCost, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control"//>
@ -689,8 +689,14 @@
refreshPDF(); refreshPDF();
}); });
$('textarea').on('keyup focus', function(e) {
while($(this).outerHeight() < this.scrollHeight + parseFloat($(this).css("borderTopWidth")) + parseFloat($(this).css("borderBottomWidth"))) {
$(this).height($(this).height()+1);
};
});
@if (Auth::user()->account->fill_products) @if (Auth::user()->account->fill_products)
$('.datalist').on('change', function() { $('.datalist').on('input', function() {
var key = $(this).val(); var key = $(this).val();
for (var i=0; i<products.length; i++) { for (var i=0; i<products.length; i++) {
var product = products[i]; var product = products[i];
@ -759,7 +765,8 @@
var design = getDesignJavascript(); var design = getDesignJavascript();
if (!design) return; if (!design) return;
var doc = generatePDF(invoice, design, true); var doc = generatePDF(invoice, design, true);
doc.save('Invoice-' + $('#invoice_number').val() + '.pdf'); var type = invoice.is_quote ? '{{ trans('texts.'.ENTITY_QUOTE) }}' : '{{ trans('texts.'.ENTITY_INVOICE) }}';
doc.save(type +'-' + $('#invoice_number').val() + '.pdf');
} }
function onEmailClick() { function onEmailClick() {
@ -1632,9 +1639,11 @@
model.invoice().addItem(); model.invoice().addItem();
} }
/*
$('.word-wrap').each(function(index, input) { $('.word-wrap').each(function(index, input) {
$(input).height($(input).val().split('\n').length * 20); $(input).height($(input).val().split('\n').length * 20);
}); });
*/
} }
function onTaxRateChange() function onTaxRateChange()

View File

@ -1,13 +1,7 @@
@extends('header') @extends('header')
@section('onReady')
$('input#name').focus();
@stop
@section('content') @section('content')
{!! Former::open($url)->addClass('col-md-10 col-md-offset-1 warn-on-exit')->method($method)->rules(array( {!! Former::open($url)->addClass('col-md-10 col-md-offset-1 warn-on-exit')->method($method)->rules(array(
'client' => 'required', 'client' => 'required',
'invoice' => 'required', 'invoice' => 'required',
@ -66,6 +60,13 @@
$('#payment_type_id').combobox(); $('#payment_type_id').combobox();
@if (!$clientPublicId)
$('.client-select input.form-control').focus();
@elseif (!$invoicePublicId)
$('.invoice-select input.form-control').focus();
@elseif (!$payment)
$('#amount').focus();
@endif
}); });
</script> </script>

View File

@ -35,3 +35,7 @@
{!! Former::close() !!} {!! Former::close() !!}
@stop @stop
@section('onReady')
$('#first_name').focus();
@stop