bug fixes

This commit is contained in:
Hillel Coren 2014-02-01 22:01:32 +02:00
parent 41db8a09f0
commit 71993f850a
17 changed files with 149 additions and 79 deletions

View File

@ -302,6 +302,12 @@ class AccountController extends \BaseController {
$csv = new parseCSV(); $csv = new parseCSV();
$csv->heading = false; $csv->heading = false;
$csv->auto($name); $csv->auto($name);
if (count($csv->data) + Client::scope()->count() > MAX_NUM_CLIENTS)
{
Session::flash('error', "Sorry, this wll exceed the limit of " . MAX_NUM_CLIENTS . " clients");
return Redirect::to('account/import');
}
Session::put('data', $csv->data); Session::put('data', $csv->data);

View File

@ -67,6 +67,11 @@ class ClientController extends \BaseController {
*/ */
public function create() public function create()
{ {
if (Client::scope()->count() > MAX_NUM_CLIENTS)
{
return View::make('error', ['error' => "Sorry, you've exceeded the limit of " . MAX_NUM_CLIENTS . " clients"]);
}
$data = array( $data = array(
'client' => null, 'client' => null,
'method' => 'POST', 'method' => 'POST',
@ -152,15 +157,21 @@ class ClientController extends \BaseController {
); );
$validator = Validator::make(Input::all(), $rules); $validator = Validator::make(Input::all(), $rules);
if ($validator->fails()) { if ($validator->fails())
{
$url = $publicId ? 'clients/' . $publicId . '/edit' : 'clients/create'; $url = $publicId ? 'clients/' . $publicId . '/edit' : 'clients/create';
return Redirect::to($url) return Redirect::to($url)
->withErrors($validator) ->withErrors($validator)
->withInput(Input::except('password')); ->withInput(Input::except('password'));
} else { }
if ($publicId) { else
{
if ($publicId)
{
$client = Client::scope($publicId)->firstOrFail(); $client = Client::scope($publicId)->firstOrFail();
} else { }
else
{
$client = Client::createNew(); $client = Client::createNew();
} }

View File

@ -324,9 +324,10 @@ class InvoiceController extends \BaseController {
$invoiceNumber = Auth::user()->account->getNextInvoiceNumber(); $invoiceNumber = Auth::user()->account->getNextInvoiceNumber();
$account = Account::with('country')->findOrFail(Auth::user()->account_id); $account = Account::with('country')->findOrFail(Auth::user()->account_id);
if ($clientPublicId) { if ($clientPublicId)
{
$client = Client::scope($clientPublicId)->firstOrFail(); $client = Client::scope($clientPublicId)->firstOrFail();
} }
$data = array( $data = array(
'account' => $account, 'account' => $account,

View File

@ -414,7 +414,7 @@ class ConfideSetupUsersTable extends Migration {
$t->softDeletes(); $t->softDeletes();
$t->string('product_key'); $t->string('product_key');
$t->string('notes'); $t->text('notes');
$t->decimal('cost', 13, 4); $t->decimal('cost', 13, 4);
$t->decimal('qty', 13, 4); $t->decimal('qty', 13, 4);

View File

@ -120,6 +120,8 @@ class ConstantsSeeder extends Seeder
Currency::create(array('name' => 'US Dollar', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); Currency::create(array('name' => 'US Dollar', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'));
Currency::create(array('name' => 'Pound Sterling', 'symbol' => '£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); Currency::create(array('name' => 'Pound Sterling', 'symbol' => '£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'));
Currency::create(array('name' => 'Euro', 'symbol' => '€', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'));
DatetimeFormat::create(array('format' => 'd/M/Y g:i a', 'label' => '10/Mar/2013')); DatetimeFormat::create(array('format' => 'd/M/Y g:i a', 'label' => '10/Mar/2013'));
DatetimeFormat::create(array('format' => 'd-M-Yk g:i a', 'label' => '10-Mar-2013')); DatetimeFormat::create(array('format' => 'd-M-Yk g:i a', 'label' => '10-Mar-2013'));

View File

@ -13,7 +13,13 @@
App::before(function($request) App::before(function($request)
{ {
// if (App::environment() == ENV_PRODUCTION)
{
if (!Request::secure())
{
return Redirect::secure(Request::getRequestUri());
}
}
}); });
@ -75,7 +81,9 @@ Route::filter('csrf', function()
{ {
$token = Request::ajax() ? Request::header('X-CSRF-Token') : Input::get('_token'); $token = Request::ajax() ? Request::header('X-CSRF-Token') : Input::get('_token');
if (Session::token() != $token) { if (Session::token() != $token)
throw new Illuminate\Session\TokenMismatchException; {
return Redirect::to('/');
//throw new Illuminate\Session\TokenMismatchException;
} }
}); });

View File

@ -130,7 +130,7 @@ class Account extends Eloquent
public function getNextInvoiceNumber() public function getNextInvoiceNumber()
{ {
$invoices = Invoice::withTrashed()->scope(false, $this->id)->get(); $invoices = Invoice::withTrashed()->scope(false, $this->id)->get(['invoice_number']);
$max = 0; $max = 0;

View File

@ -105,12 +105,18 @@ class Activity extends Eloquent
$message = Utils::encodeActivity(Auth::user(), 'created', $invoice); $message = Utils::encodeActivity(Auth::user(), 'created', $invoice);
} }
$client = $invoice->client;
$adjustment = $invoice->amount;
$client->balance = $client->balance + $adjustment;
$client->save();
$activity = Activity::getBlank($invoice); $activity = Activity::getBlank($invoice);
$activity->invoice_id = $invoice->id; $activity->invoice_id = $invoice->id;
$activity->client_id = $invoice->client_id; $activity->client_id = $invoice->client_id;
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_INVOICE; $activity->activity_type_id = ACTIVITY_TYPE_CREATE_INVOICE;
$activity->message = $message; $activity->message = $message;
$activity->balance = $invoice->client->balance; $activity->balance = $client->balance;
$activity->adjustment = $adjustment;
$activity->save(); $activity->save();
} }
@ -147,13 +153,6 @@ class Activity extends Eloquent
$adjustment = 0; $adjustment = 0;
$client = $invitation->invoice->client; $client = $invitation->invoice->client;
if (!$invitation->invoice->isSent())
{
$adjustment = $invitation->invoice->amount;
$client->balance = $client->balance + $adjustment;
$client->save();
}
$activity = Activity::getBlank($invitation); $activity = Activity::getBlank($invitation);
$activity->client_id = $invitation->invoice->client_id; $activity->client_id = $invitation->invoice->client_id;
$activity->invoice_id = $invitation->invoice_id; $activity->invoice_id = $invitation->invoice_id;
@ -161,17 +160,11 @@ class Activity extends Eloquent
$activity->activity_type_id = ACTIVITY_TYPE_EMAIL_INVOICE; $activity->activity_type_id = ACTIVITY_TYPE_EMAIL_INVOICE;
$activity->message = Utils::encodeActivity(Auth::check() ? Auth::user() : null, 'emailed', $invitation->invoice, $invitation->contact); $activity->message = Utils::encodeActivity(Auth::check() ? Auth::user() : null, 'emailed', $invitation->invoice, $invitation->contact);
$activity->balance = $client->balance; $activity->balance = $client->balance;
$activity->adjustment = $adjustment;
$activity->save(); $activity->save();
} }
public static function updateInvoice($invoice) public static function updateInvoice($invoice)
{ {
if ($invoice->invoice_status_id < INVOICE_STATUS_SENT)
{
return;
}
if ($invoice->is_deleted && !$invoice->getOriginal('is_deleted')) if ($invoice->is_deleted && !$invoice->getOriginal('is_deleted'))
{ {
if ($invoice->balance > 0) if ($invoice->balance > 0)

View File

@ -134,9 +134,6 @@ class InvoiceRepository
$invoice->tax_name = ''; $invoice->tax_name = '';
} }
$invoice->save();
$invoice->invoice_items()->forceDelete();
$total = 0; $total = 0;
foreach ($data['invoice_items'] as $item) foreach ($data['invoice_items'] as $item)
@ -146,43 +143,17 @@ class InvoiceRepository
continue; continue;
} }
if ($item->product_key) $invoiceItemCost = Utils::parseFloat($item->cost);
{ $invoiceItemQty = Utils::parseFloat($item->qty);
$product = Product::findProductByKey(trim($item->product_key)); $invoiceItemTaxRate = 0;
if (!$product)
{
$product = Product::createNew();
$product->product_key = trim($item->product_key);
}
/*
$product->notes = $item->notes;
$product->cost = $item->cost;
$product->qty = $item->qty;
*/
$product->save();
}
$invoiceItem = InvoiceItem::createNew();
$invoiceItem->product_id = isset($product) ? $product->id : null;
$invoiceItem->product_key = trim($item->product_key);
$invoiceItem->notes = trim($item->notes);
$invoiceItem->cost = Utils::parseFloat($item->cost);
$invoiceItem->qty = Utils::parseFloat($item->qty);
$invoiceItem->tax_rate = 0;
if (isset($item->tax_rate) && Utils::parseFloat($item->tax_rate) > 0) if (isset($item->tax_rate) && Utils::parseFloat($item->tax_rate) > 0)
{ {
$invoiceItem->tax_rate = Utils::parseFloat($item->tax_rate); $invoiceItemTaxRate = Utils::parseFloat($item->tax_rate);
$invoiceItem->tax_name = trim($item->tax_name);
} }
$invoice->invoice_items()->save($invoiceItem); $lineTotal = $invoiceItemCost * $invoiceItemQty;
$total += $lineTotal + ($lineTotal * $invoiceItemTaxRate / 100);
$lineTotal = $invoiceItem->cost * $invoiceItem->qty;
$total += $lineTotal + ($lineTotal * $invoiceItem->tax_rate / 100);
} }
if ($invoice->discount > 0) if ($invoice->discount > 0)
@ -196,6 +167,51 @@ class InvoiceRepository
$invoice->balance = $total; $invoice->balance = $total;
$invoice->save(); $invoice->save();
$invoice->invoice_items()->forceDelete();
foreach ($data['invoice_items'] as $item)
{
if (!$item->cost && !$item->qty && !$item->product_key && !$item->notes)
{
continue;
}
if ($item->product_key)
{
$product = Product::findProductByKey(trim($item->product_key));
if (!$product)
{
$product = Product::createNew();
$product->product_key = trim($item->product_key);
}
/*
$product->notes = $item->notes;
$product->cost = $item->cost;
$product->qty = $item->qty;
*/
$product->save();
}
$invoiceItem = InvoiceItem::createNew();
$invoiceItem->product_id = isset($product) ? $product->id : null;
$invoiceItem->product_key = trim($item->product_key);
$invoiceItem->notes = trim($item->notes);
$invoiceItem->cost = Utils::parseFloat($item->cost);
$invoiceItem->qty = Utils::parseFloat($item->qty);
$invoiceItem->tax_rate = 0;
if (isset($item->tax_rate) && Utils::parseFloat($item->tax_rate) > 0)
{
$invoiceItem->tax_rate = Utils::parseFloat($item->tax_rate);
$invoiceItem->tax_name = trim($item->tax_name);
}
$invoice->invoice_items()->save($invoiceItem);
}
if ($data['set_default_terms']) if ($data['set_default_terms'])
{ {
$account = \Auth::user()->account; $account = \Auth::user()->account;

View File

@ -22,7 +22,6 @@
//dd(gethostname()); //dd(gethostname());
//Log::error('test'); //Log::error('test');
/* /*
Event::listen('illuminate.query', function($query, $bindings, $time, $name) Event::listen('illuminate.query', function($query, $bindings, $time, $name)
{ {
@ -185,6 +184,7 @@ define('DEFAULT_INVOICE_NUMBER', '0001');
define('RECENTLY_VIEWED_LIMIT', 8); define('RECENTLY_VIEWED_LIMIT', 8);
define('LOGGED_ERROR_LIMIT', 100); define('LOGGED_ERROR_LIMIT', 100);
define('RANDOM_KEY_LENGTH', 32); define('RANDOM_KEY_LENGTH', 32);
define('MAX_NUM_CLIENTS', 3);
define('INVOICE_STATUS_DRAFT', 1); define('INVOICE_STATUS_DRAFT', 1);
define('INVOICE_STATUS_SENT', 2); define('INVOICE_STATUS_SENT', 2);

View File

@ -8,10 +8,10 @@
<script src="{{ asset('vendor/jquery-ui/ui/minified/jquery-ui.min.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/jquery-ui/ui/minified/jquery-ui.min.js') }}" type="text/javascript"></script>
<script src="{{ asset('vendor/bootstrap/dist/js/bootstrap.min.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/bootstrap/dist/js/bootstrap.min.js') }}" type="text/javascript"></script>
<script src="{{ asset('vendor/datatables/media/js/jquery.dataTables.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/datatables/media/js/jquery.dataTables.js') }}" type="text/javascript"></script>
<script src="{{ asset('vendor/datatables-bootstrap3/BS3/assets/js/datatables.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/datatables-bootstrap3/BS3/assets/js/datatables.js') }}" type="text/javascript"></script>
<script src="{{ asset('vendor/knockout.js/knockout.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/knockout.js/knockout.js') }}" type="text/javascript"></script>
<script src="{{ asset('vendor/knockout-mapping/build/output/knockout.mapping-latest.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/knockout-mapping/build/output/knockout.mapping-latest.js') }}" type="text/javascript"></script>
<script src="{{ asset('vendor/knockout-sortable/build/knockout-sortable.min.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/knockout-sortable/build/knockout-sortable.min.js') }}" type="text/javascript"></script>
<script src="{{ asset('vendor/underscore/underscore-min.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/underscore/underscore-min.js') }}" type="text/javascript"></script>
<script src="{{ asset('vendor/bootstrap-datepicker/js/bootstrap-datepicker.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/bootstrap-datepicker/js/bootstrap-datepicker.js') }}" type="text/javascript"></script>
<script src="{{ asset('vendor/typeahead.js/dist/typeahead.min.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/typeahead.js/dist/typeahead.min.js') }}" type="text/javascript"></script>
@ -21,8 +21,9 @@
<script src="{{ asset('js/jspdf.plugin.split_text_to_size.js') }}" type="text/javascript"></script> <script src="{{ asset('js/jspdf.plugin.split_text_to_size.js') }}" type="text/javascript"></script>
<script src="{{ asset('js/script.js') }}" type="text/javascript"></script> <script src="{{ asset('js/script.js') }}" type="text/javascript"></script>
<link href="{{ asset('vendor/bootstrap/dist/css/bootstrap.min.css') }}" rel="stylesheet" type="text/css"/>
<link href="{{ asset('vendor/datatables/media/css/jquery.dataTables.css') }}" rel="stylesheet" type="text/css"> <link href="{{ asset('vendor/datatables/media/css/jquery.dataTables.css') }}" rel="stylesheet" type="text/css">
<link href="{{ asset('vendor/datatables-bootstrap3/BS3/assets/css/datatables.css') }}" rel="stylesheet" type="text/css"> <link href="{{ asset('vendor/datatables-bootstrap3/BS3/assets/css/datatables.css') }}" rel="stylesheet" type="text/css">
<link href="{{ asset('vendor/font-awesome/css/font-awesome.min.css') }}" rel="stylesheet" type="text/css"/> <link href="{{ asset('vendor/font-awesome/css/font-awesome.min.css') }}" rel="stylesheet" type="text/css"/>
<link href="{{ asset('vendor/bootstrap-datepicker/css/datepicker.css') }}" rel="stylesheet" type="text/css"/> <link href="{{ asset('vendor/bootstrap-datepicker/css/datepicker.css') }}" rel="stylesheet" type="text/css"/>
<link href="{{ asset('css/bootstrap-combobox.css') }}" rel="stylesheet" type="text/css"/> <link href="{{ asset('css/bootstrap-combobox.css') }}" rel="stylesheet" type="text/css"/>
@ -141,9 +142,13 @@
<p>&nbsp;</p> <p>&nbsp;</p>
<div class="container"> <div class="container">
@if (Session::has('message')) @if (Session::has('message'))
<div class="alert alert-info">{{ Session::get('message') }}</div> <div class="alert alert-info">{{ Session::get('message') }}</div>
@endif @endif
@if (Session::has('error'))
<div class="alert alert-danger">{{ Session::get('error') }}</div>
@endif
@yield('content') @yield('content')

View File

@ -935,8 +935,22 @@
}); });
self.clientLinkText = ko.computed(function() { self.clientLinkText = ko.computed(function() {
return self.invoice().client().public_id() ? 'Edit client details' : 'Create new client'; if (self.invoice().client().public_id())
}); {
return 'Edit client details';
}
else
{
if (clients.length > {{ MAX_NUM_CLIENTS}})
{
return '';
}
else
{
return 'Create new client';
}
}
});
} }
function InvoiceModel(data) { function InvoiceModel(data) {

View File

@ -30,8 +30,6 @@
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script> <script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]--> <![endif]-->
<link rel="stylesheet" type="text/css" href="{{ asset('vendor/bootstrap/dist/css/bootstrap.min.css') }}"/>
@yield('head') @yield('head')
</head> </head>

View File

@ -54,7 +54,7 @@
populateInvoiceComboboxes({{ $clientPublicId }}, {{ $invoicePublicId }}); populateInvoiceComboboxes({{ $clientPublicId }}, {{ $invoicePublicId }});
$('#currency_id').combobox(); $('#payment_type_id').combobox();
$('#payment_date').datepicker('update', new Date({{ strtotime(Utils::today()) * 1000 }})); $('#payment_date').datepicker('update', new Date({{ strtotime(Utils::today()) * 1000 }}));

View File

@ -1,6 +1,7 @@
@extends('master') @extends('master')
@section('head') @section('head')
<link href="{{ asset('css/bootstrap.splash.css') }}" rel="stylesheet" type="text/css"/>
<link href="{{ asset('css/splash.css') }}" rel="stylesheet" type="text/css"/> <link href="{{ asset('css/splash.css') }}" rel="stylesheet" type="text/css"/>
<link href='http://fonts.googleapis.com/css?family=Roboto:400,700,900,100' rel='stylesheet' type='text/css'> <link href='http://fonts.googleapis.com/css?family=Roboto:400,700,900,100' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Roboto+Slab:400,300,700' rel='stylesheet' type='text/css'> <link href='http://fonts.googleapis.com/css?family=Roboto+Slab:400,300,700' rel='stylesheet' type='text/css'>
@ -68,7 +69,7 @@
<h1>THE <span style="color:#2299c0">SIMPLE</span> &amp; <h1>THE <span style="color:#2299c0">SIMPLE</span> &amp;
<span style="color:#edd71e">FREE</span> WAY TO INVOICE <span style="color:#edd71e">FREE</span> WAY TO INVOICE
CLIENTS</h1> CLIENTS</h1>
<p>It's just that easy. Stop spending time on <p>It's that easy. Stop spending time on
complicated and expensive invoicing.<br> complicated and expensive invoicing.<br>
No fuss, just get started and <span style= No fuss, just get started and <span style=
"color:#2299c0">get paid.</span></p> "color:#2299c0">get paid.</span></p>
@ -122,8 +123,8 @@
<div class="box"> <div class="box">
<div class="icon"><img src= <div class="icon"><img src=
"images/icon-payment.png"></div> "images/icon-payment.png"></div>
<h2>SUPPORTS ALL PAYMENT PORTALS</h2> <h2>ONLINE PAYMENTS</h2>
<p>PayPal? Authorize.Net? BeanStream? Stripe? We support all payment technologies and if you need help well lend a hand (were pretty friendly).</p> <p>PayPal? Authorize.Net? Stripe? We support all payment technologies and if you need help well lend a hand (were pretty friendly).</p>
</div> </div>
</div> </div>
</div> </div>
@ -134,10 +135,10 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h1>2.500 <span>sent invoices</span></h1> <!--<h1>2.500 <span>sent invoices</span></h1>-->
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<h1>$350.456 <span>billed</span></h1> <!--<h1>$350.456 <span>billed</span></h1>-->
</div> </div>
</div> </div>
</div> </div>

11
public/css/bootstrap.splash.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -138,6 +138,10 @@ table.invoice-table tbody tr:hover {
vertical-align: middle !important; vertical-align: middle !important;
} }
.invoice-table tfoot tr {
height: 30px;
}
.fa-bars { .fa-bars {
cursor: move !important; cursor: move !important;
} }