bug fixes

This commit is contained in:
Hillel Coren 2014-01-02 01:12:33 +02:00
parent 689d1938e1
commit 0b8ad35d66
14 changed files with 161 additions and 101 deletions

View File

@ -58,4 +58,5 @@ Configure config/database.php and then initialize the database
* [thomaspark/bootswatch](https://github.com/thomaspark/bootswatch) - Themes for Bootstrap * [thomaspark/bootswatch](https://github.com/thomaspark/bootswatch) - Themes for Bootstrap
* [mozilla/pdf.js](https://github.com/mozilla/pdf.js) - PDF Reader in JavaScript * [mozilla/pdf.js](https://github.com/mozilla/pdf.js) - PDF Reader in JavaScript
* [nnnick/Chart.js](https://github.com/nnnick/Chart.js) - Simple HTML5 Charts using the <canvas> tag * [nnnick/Chart.js](https://github.com/nnnick/Chart.js) - Simple HTML5 Charts using the <canvas> tag
* [josscrowcroft/accounting.js](https://github.com/josscrowcroft/accounting.js) - A lightweight JavaScript library for number, money and currency formatting * [josscrowcroft/accounting.js](https://github.com/josscrowcroft/accounting.js) - A lightweight JavaScript library for number, money and currency formatting
* [jashkenas/underscore](https://github.com/jashkenas/underscore) - JavaScript's utility _ belt

View File

@ -112,8 +112,9 @@ class CreditController extends \BaseController {
{ {
$rules = array( $rules = array(
'client' => 'required', 'client' => 'required',
'amount' => 'required' 'amount' => 'required',
); );
$validator = Validator::make(Input::all(), $rules); $validator = Validator::make(Input::all(), $rules);
if ($validator->fails()) { if ($validator->fails()) {

View File

@ -216,8 +216,7 @@ class InvoiceController extends \BaseController {
if (!$ref) if (!$ref)
{ {
var_dump($response); Utils::fatalError('Sorry, there was an error processing your payment. Please try again later.<p>');
exit('Sorry, there was an error processing your payment. Please try again later.');
} }
$payment = Payment::createNew(); $payment = Payment::createNew();
@ -225,7 +224,7 @@ class InvoiceController extends \BaseController {
$payment->invoice_id = $invoice->id; $payment->invoice_id = $invoice->id;
$payment->amount = $invoice->amount; $payment->amount = $invoice->amount;
$payment->client_id = $invoice->client_id; $payment->client_id = $invoice->client_id;
//$payment->contact_id = 0; // TODO_FIX $payment->contact_id = $invitation->contact_id;
$payment->transaction_reference = $ref; $payment->transaction_reference = $ref;
$payment->save(); $payment->save();
@ -299,7 +298,7 @@ class InvoiceController extends \BaseController {
public function edit($publicId) public function edit($publicId)
{ {
$invoice = Invoice::scope($publicId)->with('account.country', 'client', 'invoice_items')->firstOrFail(); $invoice = Invoice::scope($publicId)->with('account.country', 'client.contacts', 'invoice_items')->firstOrFail();
Utils::trackViewed($invoice->invoice_number . ' - ' . $invoice->client->getDisplayName(), ENTITY_INVOICE); Utils::trackViewed($invoice->invoice_number . ' - ' . $invoice->client->getDisplayName(), ENTITY_INVOICE);
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date); $invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
@ -420,12 +419,6 @@ class InvoiceController extends \BaseController {
$account->save(); $account->save();
} }
if ($action == 'email' && $invoice->invoice_status_id == INVOICE_STATUS_DRAFT)
{
$client->balance = $client->balance + $invoice->amount;
$client->save();
}
$client->load('contacts'); $client->load('contacts');
$sendInvoiceIds = []; $sendInvoiceIds = [];

View File

@ -75,7 +75,7 @@ class PaymentController extends \BaseController
$data = array( $data = array(
'clientPublicId' => $clientPublicId, 'clientPublicId' => $clientPublicId,
'invoice' => null, 'invoice' => null,
'invoices' => Invoice::scope()->with('client')->orderBy('invoice_number')->get(), 'invoices' => Invoice::scope()->with('client')->where('balance','>',0)->orderBy('invoice_number')->get(),
'payment' => null, 'payment' => null,
'method' => 'POST', 'method' => 'POST',
'url' => 'payments', 'url' => 'payments',

View File

@ -2,9 +2,15 @@
class Utils class Utils
{ {
public static function fatalError($error) public static function fatalError($error = false)
{ {
if (!$error)
{
$error = "An error occurred, please try again later";
}
Log::error($error); Log::error($error);
return View::make('error')->with('error', $error); return View::make('error')->with('error', $error);
} }

View File

@ -42,7 +42,7 @@ class Activity extends Eloquent
$activity->user_id = $entity->user_id; $activity->user_id = $entity->user_id;
$activity->account_id = $entity->account_id; $activity->account_id = $entity->account_id;
} else { } else {
exit; // TODO_FIX log error Utils::fatalError();
} }
return $activity; return $activity;
@ -104,11 +104,11 @@ class Activity extends Eloquent
public static function emailInvoice($invitation) public static function emailInvoice($invitation)
{ {
$adjustment = 0; $adjustment = 0;
$client = $invitation->invoice->client;
if (!$invitation->invoice->isSent()) if (!$invitation->invoice->isSent())
{ {
$adjustment = $invitation->invoice->amount; $adjustment = $invitation->invoice->amount;
$client = $invitation->invoice->client;
$client->balance = $client->balance + $adjustment; $client->balance = $client->balance + $adjustment;
$client->save(); $client->save();
} }
@ -120,7 +120,7 @@ class Activity extends Eloquent
$activity->contact_id = $invitation->contact_id; $activity->contact_id = $invitation->contact_id;
$activity->activity_type_id = ACTIVITY_TYPE_EMAIL_INVOICE; $activity->activity_type_id = ACTIVITY_TYPE_EMAIL_INVOICE;
$activity->message = $userName . ' emailed invoice ' . link_to('invoices/'.$invitation->invoice->public_id, $invitation->invoice->invoice_number) . ' to ' . $invitation->contact->getFullName() . ' - ' . $invitation->contact->email; $activity->message = $userName . ' emailed invoice ' . link_to('invoices/'.$invitation->invoice->public_id, $invitation->invoice->invoice_number) . ' to ' . $invitation->contact->getFullName() . ' - ' . $invitation->contact->email;
$activity->balance = $invitation->invoice->client->balance; $activity->balance = $client->balance;
$activity->adjustment = $adjustment; $activity->adjustment = $adjustment;
$activity->save(); $activity->save();
} }
@ -176,9 +176,16 @@ class Activity extends Eloquent
} }
$activity->payment_id = $payment->id; $activity->payment_id = $payment->id;
if ($payment->invoice_id) {
if ($payment->invoice_id)
{
$activity->invoice_id = $payment->invoice_id; $activity->invoice_id = $payment->invoice_id;
$invoice = $payment->invoice;
$invoice->balance = $invoice->balance - $payment->amount;
$invoice->save();
} }
$activity->client_id = $payment->client_id; $activity->client_id = $payment->client_id;
$activity->currency_id = $payment->currency_id; $activity->currency_id = $payment->currency_id;
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_PAYMENT; $activity->activity_type_id = ACTIVITY_TYPE_CREATE_PAYMENT;
@ -197,6 +204,16 @@ class Activity extends Eloquent
$activity->message = Auth::user()->getFullName() . ' created credit'; $activity->message = Auth::user()->getFullName() . ' created credit';
$activity->credit_id = $credit->id; $activity->credit_id = $credit->id;
$activity->client_id = $credit->client_id; $activity->client_id = $credit->client_id;
if ($credit->invoice_id)
{
$activity->invoice_id = $payment->invoice_id;
$invoice = $credit->invoice;
$invoice->balance = $invoice->amount - $credit->amount;
$invoice->save();
}
$activity->currency_id = $credit->currency_id; $activity->currency_id = $credit->currency_id;
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_CREDIT; $activity->activity_type_id = ACTIVITY_TYPE_CREATE_CREDIT;
$activity->balance = $client->balance; $activity->balance = $client->balance;

View File

@ -15,7 +15,7 @@ class EntityModel extends Eloquent
$entity->user_id = $parent->user_id; $entity->user_id = $parent->user_id;
$entity->account_id = $parent->account_id; $entity->account_id = $parent->account_id;
} else { } else {
exit; // TODO_FIX Utils::fatalError();
} }
$lastEntity = $className::withTrashed()->scope(false, $entity->account_id)->orderBy('public_id', 'DESC')->first(); $lastEntity = $className::withTrashed()->scope(false, $entity->account_id)->orderBy('public_id', 'DESC')->first();

View File

@ -106,7 +106,7 @@ class Invoice extends EntityModel
case FREQUENCY_ANNUALLY: case FREQUENCY_ANNUALLY:
return ($dayOfMonthStart == $dayOfMonthToday && (!$daysSinceLastSent || $monthsSinceLastSent == 12)) || $daysSinceLastSent > (12 *31); return ($dayOfMonthStart == $dayOfMonthToday && (!$daysSinceLastSent || $monthsSinceLastSent == 12)) || $daysSinceLastSent > (12 *31);
default: default:
echo "Error: invalid frequency_id - ".$this->frequency_id; exit; //TODO_FIX Utils::fatalError("Invalid frequency supplied: " . $this->frequency_id);
break; break;
} }

View File

@ -71,6 +71,8 @@ class ClientRepository
} }
} }
$client->save();
return $client; return $client;
} }
} }

View File

@ -22,6 +22,7 @@
<script type="text/javascript" src="{{ asset('js/knockout.mapping-latest.js') }}"></script> <script type="text/javascript" src="{{ asset('js/knockout.mapping-latest.js') }}"></script>
<script src="{{ asset('js/knockout-sortable.js') }}" type="text/javascript"></script> <script src="{{ asset('js/knockout-sortable.js') }}" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="{{ asset('css/font-awesome.css') }}"/> <link rel="stylesheet" type="text/css" href="{{ asset('css/font-awesome.css') }}"/>
<script src="{{ asset('js/underscore-min.js') }}" type="text/javascript"></script>
<script src="{{ asset('js/jspdf.source.js') }}" type="text/javascript"></script> <script src="{{ asset('js/jspdf.source.js') }}" type="text/javascript"></script>
<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>
@ -91,15 +92,18 @@
</ul> </ul>
<div class="navbar-form navbar-right"> <div class="navbar-form navbar-right">
@if (Auth::check() && Auth::user()->registered) @if (!Auth::check() || !Auth::user()->registered)
{{ Auth::user()->email }} &nbsp; {{ Button::sm_primary('Sign up', array('data-toggle'=>'modal', 'data-target'=>'#signUpModal')) }}
@else
{{ Button::sm_primary('Sign up', array('data-toggle'=>'modal', 'data-target'=>'#signUpModal')) }}
@endif @endif
<div class="btn-group"> <div class="btn-group">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown"> <button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
My Account <span class="caret"></span> @if (Auth::check() && Auth::user()->registered)
{{ Auth::user()->getFullName() }}
@else
My Account
@endif
<span class="caret"></span>
</button> </button>
<ul class="dropdown-menu" role="menu"> <ul class="dropdown-menu" role="menu">
<li>{{ link_to('account/details', 'Details') }}</li> <li>{{ link_to('account/details', 'Details') }}</li>
@ -359,7 +363,7 @@
$('#signUpModal').on('shown.bs.modal', function () { $('#signUpModal').on('shown.bs.modal', function () {
$(['first_name','last_name','email','password']).each(function(i, field) { $(['first_name','last_name','email','password']).each(function(i, field) {
var $input = $('form.signUpForm #'+field); var $input = $('form.signUpForm #new_'+field);
if (!$input.val()) { if (!$input.val()) {
$input.focus(); $input.focus();
return false; return false;

View File

@ -36,7 +36,7 @@
<div class="form-group" style="margin-bottom: 8px"> <div class="form-group" style="margin-bottom: 8px">
<div class="col-lg-8 col-sm-8 col-lg-offset-4 col-sm-offset-4"> <div class="col-lg-8 col-sm-8 col-lg-offset-4 col-sm-offset-4">
<a href="#" data-bind="click: $root.showClientForm, text: client.linkText"></a> <a href="#" data-bind="click: $root.showClientForm, text: $root.clientLinkText"></a>
</div> </div>
</div> </div>
@ -204,12 +204,12 @@
array('Delete Invoice', "javascript:onDeleteClick()"), array('Delete Invoice', "javascript:onDeleteClick()"),
) )
) )
, array('id'=>'actionDropDown', 'style'=>'text-align:left', 'data-bind'=>'css: enable.save'))->split(); }} , array('id'=>'actionDropDown', 'style'=>'text-align:left', 'data-bind'=>'css: $root.enable.save'))->split(); }}
@else @else
{{ Button::primary_submit('Save Invoice', array('data-bind'=>'css: enable.save')) }} {{ Button::primary_submit('Save Invoice', array('data-bind'=>'css: $root.enable.save')) }}
@endif @endif
{{ Button::primary('Send Email', array('id' => 'email_button', 'onclick' => 'onEmailClick()', 'data-bind' => 'css: enable.email')) }} {{ Button::primary('Send Email', array('id' => 'email_button', 'onclick' => 'onEmailClick()', 'data-bind' => 'css: $root.enable.email')) }}
</div> </div>
<p>&nbsp;</p> <p>&nbsp;</p>
@ -326,7 +326,7 @@
<input onkeyup="onTaxRateChange()" data-bind="value: prettyRate, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control" onchange="refreshPDF()"//> <input onkeyup="onTaxRateChange()" data-bind="value: prettyRate, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control" onchange="refreshPDF()"//>
</td> </td>
<td style="width:10px; cursor:pointer" class="hide-border td-icon"> <td style="width:10px; cursor:pointer" class="hide-border td-icon">
&nbsp;<i data-bind="click: $root.removeTaxRate, visible: actionsVisible() &amp;&amp; $root.tax_rates().length > 1" class="fa fa-minus-circle" title="Remove item"/> &nbsp;<i data-bind="click: $root.removeTaxRate, visible: actionsVisible() &amp;&amp; !isEmpty()" class="fa fa-minus-circle" title="Remove item"/>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -380,7 +380,7 @@
model.loadClient($.parseJSON(ko.toJSON(new ClientModel()))); model.loadClient($.parseJSON(ko.toJSON(new ClientModel())));
} }
refreshPDF(); refreshPDF();
}).trigger('change'); }); //.trigger('change');
$('#terms, #public_notes, #invoice_number, #invoice_date, #due_date, #po_number, #discout, #currency_id').change(function() { $('#terms, #public_notes, #invoice_number, #invoice_date, #due_date, #po_number, #discout, #currency_id').change(function() {
refreshPDF(); refreshPDF();
@ -410,7 +410,9 @@
$('#taxModal').on('shown.bs.modal', function () { $('#taxModal').on('shown.bs.modal', function () {
$('#taxModal input:first').focus(); $('#taxModal input:first').focus();
}).on('hidden.bs.modal', function () { }).on('hidden.bs.modal', function () {
// if the user changed the tax rates we need to trigger the
// change event on the selects for the model to get updated
$('table.invoice-table select').trigger('change');
}) })
$('#actionDropDown > button:first').click(function() { $('#actionDropDown > button:first').click(function() {
@ -418,8 +420,14 @@
}); });
$('label.radio').addClass('radio-inline'); $('label.radio').addClass('radio-inline');
var client = model.invoice().client();
setComboboxValue($('.client_select'),
client.public_id(),
client.name.display());
applyComboboxListeners(); applyComboboxListeners();
refreshPDF();
}); });
function applyComboboxListeners() { function applyComboboxListeners() {
@ -534,6 +542,11 @@
return; return;
} }
event.preventDefault(); event.preventDefault();
if (model.enable.save() != 'enabled') {
return;
}
$('.main_form').submit(); $('.main_form').submit();
return false; return false;
} }
@ -609,9 +622,20 @@
}); });
self.tax_rates.filtered = ko.computed(function() { self.tax_rates.filtered = ko.computed(function() {
return self.tax_rates().slice(1, self.tax_rates().length); var i = 0;
}); for (i; i<self.tax_rates().length; i++) {
var taxRate = self.tax_rates()[i];
if (taxRate.isEmpty()) {
break;
}
}
//console.log('i is %s', i);
var rates = self.tax_rates().concat();
rates.splice(i, 1);
return rates;
});
self.removeTaxRate = function(taxRate) { self.removeTaxRate = function(taxRate) {
self.tax_rates.remove(taxRate); self.tax_rates.remove(taxRate);
@ -622,8 +646,9 @@
var itemModel = new TaxRateModel(data); var itemModel = new TaxRateModel(data);
self.tax_rates.push(itemModel); self.tax_rates.push(itemModel);
applyComboboxListeners(); applyComboboxListeners();
} }
/*
self.getBlankTaxRate = function() { self.getBlankTaxRate = function() {
for (var i=0; i<self.tax_rates().length; i++) { for (var i=0; i<self.tax_rates().length; i++) {
var taxRate = self.tax_rates()[i]; var taxRate = self.tax_rates()[i];
@ -632,6 +657,7 @@
} }
} }
} }
*/
self.getTaxRate = function(name, rate) { self.getTaxRate = function(name, rate) {
for (var i=0; i<self.tax_rates().length; i++) { for (var i=0; i<self.tax_rates().length; i++) {
@ -640,10 +666,11 @@
return taxRate; return taxRate;
} }
} }
var taxRate = new TaxRateModel(); var taxRate = new TaxRateModel();
taxRate.name(name); taxRate.name(name);
taxRate.rate(parseFloat(rate)); taxRate.rate(parseFloat(rate));
taxRate.is_deleted(true); if (parseFloat(rate) > 0) taxRate.is_deleted(true);
self.tax_rates.push(taxRate); self.tax_rates.push(taxRate);
return taxRate; return taxRate;
} }
@ -688,9 +715,11 @@
name = email; name = email;
} }
$('.client_select select').combobox('setSelected'); setComboboxValue($('.client_select'), -1, name);
$('.client_select input.form-control').val(name);
$('.client_select .combobox-container').addClass('combobox-selected'); //$('.client_select select').combobox('setSelected');
//$('.client_select input.form-control').val(name);
//$('.client_select .combobox-container').addClass('combobox-selected');
$('#emailError').css( "display", "none" ); $('#emailError').css( "display", "none" );
//$('.client_select input.form-control').focus(); //$('.client_select input.form-control').focus();
@ -700,6 +729,44 @@
model.clientBackup = false; model.clientBackup = false;
$('#clientModal').modal('hide'); $('#clientModal').modal('hide');
} }
self.enable = {};
self.enable.save = ko.computed(function() {
var isValid = false;
for (var i=0; i<self.invoice().client().contacts().length; i++) {
var contact = self.invoice().client().contacts()[i];
if (isValidEmailAddress(contact.email())) {
isValid = true;
} else {
isValid = false;
break;
}
}
return isValid ? "enabled" : "disabled";
});
self.enable.email = ko.computed(function() {
var isValid = false;
var sendTo = false;
for (var i=0; i<self.invoice().client().contacts().length; i++) {
var contact = self.invoice().client().contacts()[i];
if (isValidEmailAddress(contact.email())) {
isValid = true;
if (contact.send_invoice()) {
sendTo = true;
}
} else {
isValid = false;
break;
}
}
return isValid && sendTo ? "enabled" : "disabled";
});
self.clientLinkText = ko.computed(function() {
return self.invoice().client().public_id() ? 'Edit client details' : 'Create new client';
});
} }
function InvoiceModel(data) { function InvoiceModel(data) {
@ -708,7 +775,7 @@
this.id = ko.observable(''); this.id = ko.observable('');
self.discount = ko.observable(''); self.discount = ko.observable('');
self.frequency_id = ko.observable(''); self.frequency_id = ko.observable('');
self.currency_id = ko.observable({{ Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY) }}); self.currency_id = ko.observable({{ Session::get(SESSION_CURRENCY) }});
self.terms = ko.observable(wordWrapText('{{ $account->invoice_terms }}', 340)); self.terms = ko.observable(wordWrapText('{{ $account->invoice_terms }}', 340));
self.public_notes = ko.observable(''); self.public_notes = ko.observable('');
self.po_number = ko.observable(''); self.po_number = ko.observable('');
@ -799,43 +866,6 @@
owner: this owner: this
}); });
self.client.linkText = ko.computed(function() {
return self.client().public_id() ? 'Edit client details' : 'Create new client';
});
self.enable = {};
self.enable.save = ko.computed(function() {
var isValid = false;
for (var i=0; i<self.client().contacts().length; i++) {
var contact = self.client().contacts()[i];
if (isValidEmailAddress(contact.email())) {
isValid = true;
} else {
isValid = false;
break;
}
}
return isValid ? "enabled" : "disabled";
});
self.enable.email = ko.computed(function() {
var isValid = false;
var sendTo = false;
for (var i=0; i<self.client().contacts().length; i++) {
var contact = self.client().contacts()[i];
if (isValidEmailAddress(contact.email())) {
isValid = true;
if (contact.send_invoice()) {
sendTo = true;
}
} else {
isValid = false;
break;
}
}
return isValid && sendTo ? "enabled" : "disabled";
});
self.removeItem = function(item) { self.removeItem = function(item) {
self.invoice_items.remove(item); self.invoice_items.remove(item);
@ -933,6 +963,7 @@
} }
} }
self.showContact = function(elem) { if (elem.nodeType === 1) $(elem).hide().slideDown() } self.showContact = function(elem) { if (elem.nodeType === 1) $(elem).hide().slideDown() }
self.hideContact = function(elem) { if (elem.nodeType === 1) $(elem).slideUp(function() { $(elem).remove(); }) } self.hideContact = function(elem) { if (elem.nodeType === 1) $(elem).slideUp(function() { $(elem).remove(); }) }
@ -949,17 +980,19 @@
self.contacts.remove(this); self.contacts.remove(this);
} }
/* self.name.display = ko.computed(function() {
self.placeholderName = ko.computed(function() { if (self.name()) {
if (self.contacts().length == 0) return; return self.name();
var contact = self.contacts()[0];
if (contact.first_name() || contact.last_name()) {
return contact.first_name() + ' ' + contact.last_name();
} else {
return '';
} }
}); if (self.contacts().length == 0) return;
*/ var contact = self.contacts()[0];
if (contact.first_name() || contact.last_name()) {
return contact.first_name() + ' ' + contact.last_name();
} else {
return contact.email();
}
});
if (data) { if (data) {
ko.mapping.fromJS(data, {}, this); ko.mapping.fromJS(data, {}, this);
@ -992,6 +1025,7 @@
self.rate = ko.observable(0); self.rate = ko.observable(0);
self.name = ko.observable(''); self.name = ko.observable('');
self.is_deleted = ko.observable(false); self.is_deleted = ko.observable(false);
self.is_blank = ko.observable(false);
self.actionsVisible = ko.observable(false); self.actionsVisible = ko.observable(false);
if (data) { if (data) {
@ -1012,7 +1046,7 @@
self.displayName = ko.computed({ self.displayName = ko.computed({
read: function () { read: function () {
var name = self.name() ? self.name() : ''; var name = self.name() ? self.name() : '';
var rate = self.rate() ? parseFloat(self.rate()) + '% -' : ''; var rate = self.rate() ? parseFloat(self.rate()) + '% ' : '';
return rate + name; return rate + name;
}, },
write: function (value) { write: function (value) {
@ -1086,8 +1120,7 @@
if (data) { if (data) {
ko.mapping.fromJS(data, self.mapping, this); ko.mapping.fromJS(data, self.mapping, this);
//if (this.cost()) this.cost(formatMoney(this.cost(), parent.invoice.currency_id(), true)); // TODO_FIX //if (this.cost()) this.cost(formatMoney(this.cost(), model ? model.invoice().currency_id() : 1, true));
if (this.cost()) this.cost(formatMoney(this.cost(), 1, true));
} }
self.wrapped_notes = ko.computed({ self.wrapped_notes = ko.computed({
@ -1159,6 +1192,7 @@
function onTaxRateChange() function onTaxRateChange()
{ {
var emptyCount = 0; var emptyCount = 0;
for(var i=0; i<model.tax_rates().length; i++) { for(var i=0; i<model.tax_rates().length; i++) {
var taxRate = model.tax_rates()[i]; var taxRate = model.tax_rates()[i];
if (taxRate.isEmpty()) { if (taxRate.isEmpty()) {
@ -1166,7 +1200,7 @@
} }
} }
if (emptyCount < 2) { for(var i=0; i<2-emptyCount; i++) {
model.addTaxRate(); model.addTaxRate();
} }
} }
@ -1187,12 +1221,12 @@
} }
@if ($data) @if ($data)
window.model = new ViewModel({{ $data }}); window.model = new ViewModel({{ $data }});
@else @else
window.model = new ViewModel(); window.model = new ViewModel();
model.addTaxRate(); model.addTaxRate();
@foreach ($taxRates as $taxRate) @foreach ($taxRates as $taxRate)
model.addTaxRate({{ $taxRate }}); model.addTaxRate({{ $taxRate }});
@endforeach @endforeach
@if ($invoice) @if ($invoice)
var invoice = {{ $invoice }}; var invoice = {{ $invoice }};
@ -1203,16 +1237,18 @@
var contact = client.contacts[i]; var contact = client.contacts[i];
contact.send_invoice = invitationContactIds.indexOf(contact.public_id) >= 0; contact.send_invoice = invitationContactIds.indexOf(contact.public_id) >= 0;
} }
model.invoice().addItem();
//model.addTaxRate();
@endif @endif
model.invoice().addItem();
model.addTaxRate();
@endif @endif
model.invoice().tax(model.getTaxRate(model.invoice().tax_name(), model.invoice().tax_rate())); model.invoice().tax(model.getTaxRate(model.invoice().tax_name(), model.invoice().tax_rate()));
for (var i=0; i<model.invoice().invoice_items().length; i++) { for (var i=0; i<model.invoice().invoice_items().length; i++) {
var item = model.invoice().invoice_items()[i]; var item = model.invoice().invoice_items()[i];
item.tax(model.getTaxRate(item.tax_name(), item.tax_rate())); item.tax(model.getTaxRate(item.tax_name(), item.tax_rate()));
item.cost(parseFloat(item.cost()) > 0 ? formatMoney(item.cost(), model.invoice().currency_id(), true) : '');
} }
onTaxRateChange();
if (!model.invoice().discount()) model.invoice().discount(''); if (!model.invoice().discount()) model.invoice().discount('');

View File

@ -120,7 +120,7 @@
for (var i=0; i<list.length; i++) { for (var i=0; i<list.length; i++) {
var invoice = list[i]; var invoice = list[i];
var client = clientMap[invoice.client.public_id]; var client = clientMap[invoice.client.public_id];
$invoiceCombobox.append(new Option(invoice.invoice_number + ' - ' + getClientDisplayName(client), invoice.public_id)); $invoiceCombobox.append(new Option(invoice.invoice_number + ' - ' + getClientDisplayName(client) + ' - ' + formatMoney(invoice.balance, invoice.currency_id), invoice.public_id));
} }
$('select#invoice').combobox('refresh'); $('select#invoice').combobox('refresh');
}).trigger('change'); }).trigger('change');

View File

@ -326,6 +326,7 @@
} }
, keyup: function (e) { , keyup: function (e) {
console.log('keyCode: %s', e.keyCode);
switch(e.keyCode) { switch(e.keyCode) {
case 40: // down arrow case 40: // down arrow
case 39: // right arrow case 39: // right arrow
@ -353,7 +354,6 @@
break; break;
default: default:
console.log('keyCode: %s', e.keyCode);
this.clearTarget(); this.clearTarget();
this.lookup(); this.lookup();
} }

View File

@ -237,7 +237,7 @@ function generatePDF(invoice) {
x += 16; x += 16;
doc.text(footerLeft, x, 'Paid to Date'); doc.text(footerLeft, x, 'Paid to Date');
var paid = formatMoney(0, currencyId, true); var paid = formatMoney(invoice.amount - invoice.balance, currencyId, true);
var paidX = headerRight - (doc.getStringUnitWidth(paid) * doc.internal.getFontSize()); var paidX = headerRight - (doc.getStringUnitWidth(paid) * doc.internal.getFontSize());
doc.text(paidX, x, paid); doc.text(paidX, x, paid);
@ -246,7 +246,7 @@ function generatePDF(invoice) {
doc.setFontType("bold"); doc.setFontType("bold");
doc.text(footerLeft, x, 'Balance Due'); doc.text(footerLeft, x, 'Balance Due');
var total = formatMoney(total, currencyId); var total = formatMoney(invoice.balance, currencyId);
var totalX = headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize()); var totalX = headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize());
doc.text(totalX, x, total); doc.text(totalX, x, total);