2015-10-22 20:48:12 +02:00
|
|
|
<script type="text/javascript">
|
|
|
|
|
|
|
|
function ViewModel(data) {
|
|
|
|
var self = this;
|
|
|
|
self.showMore = ko.observable(false);
|
|
|
|
|
|
|
|
//self.invoice = data ? false : new InvoiceModel();
|
|
|
|
self.invoice = ko.observable(data ? false : new InvoiceModel());
|
2016-01-31 14:10:33 +01:00
|
|
|
self.expense_currency_id = ko.observable();
|
2016-02-29 10:40:52 +01:00
|
|
|
self.products = {!! $products !!};
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
self.loadClient = function(client) {
|
|
|
|
ko.mapping.fromJS(client, model.invoice().client().mapping, model.invoice().client);
|
2015-10-29 15:51:57 +01:00
|
|
|
@if (!$invoice->id)
|
2015-10-22 20:48:12 +02:00
|
|
|
self.setDueDate();
|
|
|
|
@endif
|
|
|
|
}
|
|
|
|
|
|
|
|
self.showMoreFields = function() {
|
|
|
|
self.showMore(!self.showMore());
|
|
|
|
}
|
|
|
|
|
|
|
|
self.setDueDate = function() {
|
|
|
|
@if ($entityType == ENTITY_INVOICE)
|
|
|
|
var paymentTerms = parseInt(self.invoice().client().payment_terms());
|
|
|
|
if (paymentTerms && paymentTerms != 0 && !self.invoice().due_date())
|
|
|
|
{
|
|
|
|
if (paymentTerms == -1) paymentTerms = 0;
|
|
|
|
var dueDate = $('#invoice_date').datepicker('getDate');
|
|
|
|
dueDate.setDate(dueDate.getDate() + paymentTerms);
|
2016-01-10 11:25:05 +01:00
|
|
|
self.invoice().due_date(dueDate);
|
|
|
|
// We're using the datepicker to handle the date formatting
|
2015-10-22 20:48:12 +02:00
|
|
|
self.invoice().due_date($('#due_date').val());
|
|
|
|
}
|
|
|
|
@endif
|
|
|
|
}
|
|
|
|
|
|
|
|
self.invoice_taxes = ko.observable({{ Auth::user()->account->invoice_taxes ? 'true' : 'false' }});
|
|
|
|
self.invoice_item_taxes = ko.observable({{ Auth::user()->account->invoice_item_taxes ? 'true' : 'false' }});
|
|
|
|
self.show_item_taxes = ko.observable({{ Auth::user()->account->show_item_taxes ? 'true' : 'false' }});
|
|
|
|
|
|
|
|
self.mapping = {
|
|
|
|
'invoice': {
|
|
|
|
create: function(options) {
|
|
|
|
return new InvoiceModel(options.data);
|
|
|
|
}
|
|
|
|
},
|
2016-01-10 11:25:05 +01:00
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
if (data) {
|
|
|
|
ko.mapping.fromJS(data, self.mapping, self);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.invoice_taxes.show = ko.computed(function() {
|
2016-03-31 11:29:01 +02:00
|
|
|
if (self.invoice().tax_name1() || self.invoice().tax_name2()) {
|
2015-10-22 20:48:12 +02:00
|
|
|
return true;
|
2016-01-10 11:25:05 +01:00
|
|
|
}
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-03-31 11:29:01 +02:00
|
|
|
return self.invoice_taxes() && {{ count($taxRateOptions) ? 'true' : 'false' }};
|
2015-10-22 20:48:12 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
self.invoice_item_taxes.show = ko.computed(function() {
|
|
|
|
if (self.invoice_item_taxes()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
for (var i=0; i<self.invoice().invoice_items().length; i++) {
|
|
|
|
var item = self.invoice().invoice_items()[i];
|
2016-03-31 11:29:01 +02:00
|
|
|
if (item.tax_name1() || item.tax_name2()) {
|
2015-10-22 20:48:12 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
self.showClientForm = function() {
|
|
|
|
trackEvent('/activity', '/view_client_form');
|
|
|
|
self.clientBackup = ko.mapping.toJS(self.invoice().client);
|
|
|
|
|
2015-11-02 23:05:28 +01:00
|
|
|
$('#emailError').css( "display", "none" );
|
|
|
|
$('#clientModal').modal('show');
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
self.clientFormComplete = function() {
|
|
|
|
trackEvent('/activity', '/save_client_form');
|
|
|
|
|
2015-11-09 12:46:53 +01:00
|
|
|
var email = $("[name='client[contacts][0][email]']").val();
|
|
|
|
var firstName = $("[name='client[contacts][0][first_name]']").val();
|
|
|
|
var lastName = $("[name='client[contacts][0][last_name]']").val();
|
2015-12-29 11:23:50 +01:00
|
|
|
var name = $("[name='client[name]']").val();
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
if (name) {
|
|
|
|
//
|
|
|
|
} else if (firstName || lastName) {
|
|
|
|
name = firstName + ' ' + lastName;
|
|
|
|
} else {
|
|
|
|
name = email;
|
|
|
|
}
|
|
|
|
|
|
|
|
var isValid = true;
|
2015-11-09 12:46:53 +01:00
|
|
|
$('input.client-email').each(function(item, value) {
|
2016-04-14 09:39:12 +02:00
|
|
|
var $email = $(value);
|
2015-10-22 20:48:12 +02:00
|
|
|
var email = $(value).val();
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-04-14 09:39:12 +02:00
|
|
|
// Trim whitespace
|
|
|
|
email = (email || '').trim();
|
|
|
|
$email.val(email);
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2015-12-29 22:55:35 +01:00
|
|
|
if (!firstName && (!email || !isValidEmailAddress(email))) {
|
2015-11-09 12:46:53 +01:00
|
|
|
isValid = false;
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!isValid) {
|
|
|
|
$('#emailError').css( "display", "inline" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self.invoice().client().public_id() == 0) {
|
|
|
|
self.invoice().client().public_id(-1);
|
|
|
|
self.invoice().client().invoice_number_counter = 1;
|
|
|
|
self.invoice().client().quote_number_counter = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
model.setDueDate();
|
|
|
|
setComboboxValue($('.client_select'), -1, name);
|
|
|
|
|
|
|
|
var client = $.parseJSON(ko.toJSON(self.invoice().client()));
|
|
|
|
setInvoiceNumber(client);
|
|
|
|
|
|
|
|
//$('.client_select select').combobox('setSelected');
|
|
|
|
//$('.client_select input.form-control').val(name);
|
|
|
|
//$('.client_select .combobox-container').addClass('combobox-selected');
|
|
|
|
|
|
|
|
$('#emailError').css( "display", "none" );
|
|
|
|
|
|
|
|
refreshPDF(true);
|
|
|
|
model.clientBackup = false;
|
|
|
|
$('#clientModal').modal('hide');
|
|
|
|
}
|
|
|
|
|
|
|
|
self.clientLinkText = ko.computed(function() {
|
|
|
|
if (self.invoice().client().public_id())
|
|
|
|
{
|
|
|
|
return "{{ trans('texts.edit_client') }}";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (clients.length > {{ Auth::user()->getMaxNumClients() }})
|
|
|
|
{
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return "{{ trans('texts.create_new_client') }}";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function InvoiceModel(data) {
|
2015-10-23 13:55:18 +02:00
|
|
|
var self = this;
|
|
|
|
this.client = ko.observable(data ? false : new ClientModel());
|
2015-10-22 20:48:12 +02:00
|
|
|
self.account = {!! $account !!};
|
|
|
|
self.id = ko.observable('');
|
|
|
|
self.discount = ko.observable('');
|
|
|
|
self.is_amount_discount = ko.observable(0);
|
2016-01-10 11:25:05 +01:00
|
|
|
self.frequency_id = ko.observable(4); // default to monthly
|
2015-10-22 20:48:12 +02:00
|
|
|
self.terms = ko.observable('');
|
2015-10-29 15:42:05 +01:00
|
|
|
self.default_terms = ko.observable(account.{{ $entityType }}_terms);
|
|
|
|
self.terms_placeholder = ko.observable({{ !$invoice->id && $account->{"{$entityType}_terms"} ? "account.{$entityType}_terms" : false}});
|
2015-10-22 20:48:12 +02:00
|
|
|
self.set_default_terms = ko.observable(false);
|
|
|
|
self.invoice_footer = ko.observable('');
|
|
|
|
self.default_footer = ko.observable(account.invoice_footer);
|
2015-10-25 08:13:06 +01:00
|
|
|
self.footer_placeholder = ko.observable({{ !$invoice->id && $account->invoice_footer ? 'account.invoice_footer' : false}});
|
2015-10-22 20:48:12 +02:00
|
|
|
self.set_default_footer = ko.observable(false);
|
2015-10-23 13:55:18 +02:00
|
|
|
self.public_notes = ko.observable('');
|
2015-10-22 20:48:12 +02:00
|
|
|
self.po_number = ko.observable('');
|
2015-10-23 13:55:18 +02:00
|
|
|
self.invoice_date = ko.observable('');
|
|
|
|
self.invoice_number = ko.observable('');
|
2015-10-22 20:48:12 +02:00
|
|
|
self.due_date = ko.observable('');
|
2016-02-11 16:12:27 +01:00
|
|
|
self.recurring_due_date = ko.observable('');
|
2015-10-23 13:55:18 +02:00
|
|
|
self.start_date = ko.observable('');
|
2016-05-22 18:51:09 +02:00
|
|
|
self.start_date_orig = ko.observable('');
|
2015-10-22 20:48:12 +02:00
|
|
|
self.end_date = ko.observable('');
|
|
|
|
self.last_sent_date = ko.observable('');
|
2016-03-31 11:29:01 +02:00
|
|
|
self.tax_name1 = ko.observable();
|
|
|
|
self.tax_rate1 = ko.observable();
|
|
|
|
self.tax_name2 = ko.observable();
|
|
|
|
self.tax_rate2 = ko.observable();
|
2015-10-28 20:22:07 +01:00
|
|
|
self.is_recurring = ko.observable(0);
|
|
|
|
self.is_quote = ko.observable({{ $entityType == ENTITY_QUOTE ? '1' : '0' }});
|
2016-05-09 22:29:02 +02:00
|
|
|
self.auto_bill = ko.observable(0);
|
|
|
|
self.client_enable_auto_bill = ko.observable(false);
|
2015-10-22 20:48:12 +02:00
|
|
|
self.invoice_status_id = ko.observable(0);
|
|
|
|
self.invoice_items = ko.observableArray();
|
2016-03-23 03:23:45 +01:00
|
|
|
self.documents = ko.observableArray();
|
2016-03-24 23:15:52 +01:00
|
|
|
self.expenses = ko.observableArray();
|
2015-10-22 20:48:12 +02:00
|
|
|
self.amount = ko.observable(0);
|
|
|
|
self.balance = ko.observable(0);
|
2015-10-23 13:55:18 +02:00
|
|
|
self.invoice_design_id = ko.observable(1);
|
|
|
|
self.partial = ko.observable(0);
|
2015-11-02 23:05:28 +01:00
|
|
|
self.has_tasks = ko.observable();
|
2016-01-10 11:25:05 +01:00
|
|
|
self.has_expenses = ko.observable();
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
self.custom_value1 = ko.observable(0);
|
|
|
|
self.custom_value2 = ko.observable(0);
|
|
|
|
self.custom_taxes1 = ko.observable(false);
|
|
|
|
self.custom_taxes2 = ko.observable(false);
|
|
|
|
self.custom_text_value1 = ko.observable();
|
|
|
|
self.custom_text_value2 = ko.observable();
|
|
|
|
|
|
|
|
self.mapping = {
|
|
|
|
'client': {
|
|
|
|
create: function(options) {
|
|
|
|
return new ClientModel(options.data);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'invoice_items': {
|
|
|
|
create: function(options) {
|
|
|
|
return new ItemModel(options.data);
|
|
|
|
}
|
|
|
|
},
|
2016-03-23 03:23:45 +01:00
|
|
|
'documents': {
|
|
|
|
create: function(options) {
|
|
|
|
return new DocumentModel(options.data);
|
|
|
|
}
|
|
|
|
},
|
2016-03-24 23:15:52 +01:00
|
|
|
'expenses': {
|
|
|
|
create: function(options) {
|
|
|
|
return new ExpenseModel(options.data);
|
|
|
|
}
|
|
|
|
},
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
self.addItem = function() {
|
2016-09-14 09:39:08 +02:00
|
|
|
if (self.invoice_items().length >= {{ MAX_INVOICE_ITEMS }}) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
var itemModel = new ItemModel();
|
|
|
|
@if ($account->hide_quantity)
|
2015-12-29 08:52:02 +01:00
|
|
|
itemModel.qty(1);
|
2015-10-22 20:48:12 +02:00
|
|
|
@endif
|
2016-01-10 11:25:05 +01:00
|
|
|
self.invoice_items.push(itemModel);
|
2015-12-29 08:52:02 +01:00
|
|
|
applyComboboxListeners();
|
2015-10-22 20:48:12 +02:00
|
|
|
return itemModel;
|
|
|
|
}
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-03-23 03:23:45 +01:00
|
|
|
self.addDocument = function() {
|
|
|
|
var documentModel = new DocumentModel();
|
|
|
|
self.documents.push(documentModel);
|
|
|
|
return documentModel;
|
|
|
|
}
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-03-24 20:13:54 +01:00
|
|
|
self.removeDocument = function(doc) {
|
|
|
|
var public_id = doc.public_id?doc.public_id():doc;
|
2016-03-23 03:23:45 +01:00
|
|
|
self.documents.remove(function(document) {
|
|
|
|
return document.public_id() == public_id;
|
|
|
|
});
|
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
if (data) {
|
2015-12-29 08:52:02 +01:00
|
|
|
ko.mapping.fromJS(data, self.mapping, self);
|
2015-10-22 20:48:12 +02:00
|
|
|
} else {
|
|
|
|
self.addItem();
|
|
|
|
}
|
|
|
|
|
|
|
|
self.qtyLabel = ko.computed(function() {
|
|
|
|
return self.has_tasks() ? invoiceLabels['hours'] : invoiceLabels['quantity'];
|
|
|
|
}, this);
|
|
|
|
|
|
|
|
self.costLabel = ko.computed(function() {
|
|
|
|
return self.has_tasks() ? invoiceLabels['rate'] : invoiceLabels['unit_cost'];
|
|
|
|
}, this);
|
|
|
|
|
2016-03-31 11:29:01 +02:00
|
|
|
this.tax1 = ko.computed({
|
|
|
|
read: function () {
|
|
|
|
return self.tax_rate1() + ' ' + self.tax_name1();
|
|
|
|
},
|
|
|
|
write: function(value) {
|
|
|
|
var rate = value.substr(0, value.indexOf(' '));
|
|
|
|
var name = value.substr(value.indexOf(' ') + 1);
|
|
|
|
self.tax_name1(name);
|
|
|
|
self.tax_rate1(rate);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
this.tax2 = ko.computed({
|
2015-10-22 20:48:12 +02:00
|
|
|
read: function () {
|
2016-03-31 11:29:01 +02:00
|
|
|
return self.tax_rate2() + ' ' + self.tax_name2();
|
2015-10-22 20:48:12 +02:00
|
|
|
},
|
|
|
|
write: function(value) {
|
2016-03-27 17:06:02 +02:00
|
|
|
var rate = value.substr(0, value.indexOf(' '));
|
|
|
|
var name = value.substr(value.indexOf(' ') + 1);
|
2016-03-31 11:29:01 +02:00
|
|
|
self.tax_name2(name);
|
|
|
|
self.tax_rate2(rate);
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
})
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2015-10-22 20:48:12 +02:00
|
|
|
self.removeItem = function(item) {
|
|
|
|
self.invoice_items.remove(item);
|
|
|
|
refreshPDF(true);
|
|
|
|
}
|
|
|
|
|
2015-12-07 14:34:55 +01:00
|
|
|
self.formatMoney = function(amount) {
|
|
|
|
var client = $.parseJSON(ko.toJSON(self.client()));
|
|
|
|
return formatMoneyAccount(amount, self.account, client);
|
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
self.totals = ko.observable();
|
|
|
|
|
|
|
|
self.totals.rawSubtotal = ko.computed(function() {
|
|
|
|
var total = 0;
|
|
|
|
for(var p=0; p < self.invoice_items().length; ++p) {
|
|
|
|
var item = self.invoice_items()[p];
|
|
|
|
total += item.totals.rawTotal();
|
|
|
|
}
|
|
|
|
return total;
|
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.subtotal = ko.computed(function() {
|
|
|
|
var total = self.totals.rawSubtotal();
|
2015-12-07 14:34:55 +01:00
|
|
|
return self.formatMoney(total);
|
2015-10-22 20:48:12 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.rawDiscounted = ko.computed(function() {
|
|
|
|
if (parseInt(self.is_amount_discount())) {
|
|
|
|
return roundToTwo(self.discount());
|
|
|
|
} else {
|
2016-01-10 11:25:05 +01:00
|
|
|
return roundToTwo(self.totals.rawSubtotal() * (self.discount()/100));
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.discounted = ko.computed(function() {
|
2015-12-07 14:34:55 +01:00
|
|
|
return self.formatMoney(self.totals.rawDiscounted());
|
2015-10-22 20:48:12 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.taxAmount = ko.computed(function() {
|
|
|
|
var total = self.totals.rawSubtotal();
|
|
|
|
var discount = self.totals.rawDiscounted();
|
|
|
|
total -= discount;
|
|
|
|
|
|
|
|
var customValue1 = roundToTwo(self.custom_value1());
|
|
|
|
var customValue2 = roundToTwo(self.custom_value2());
|
|
|
|
var customTaxes1 = self.custom_taxes1() == 1;
|
|
|
|
var customTaxes2 = self.custom_taxes2() == 1;
|
|
|
|
|
|
|
|
if (customValue1 && customTaxes1) {
|
|
|
|
total = NINJA.parseFloat(total) + customValue1;
|
|
|
|
}
|
|
|
|
if (customValue2 && customTaxes2) {
|
|
|
|
total = NINJA.parseFloat(total) + customValue2;
|
|
|
|
}
|
|
|
|
|
2016-03-31 11:29:01 +02:00
|
|
|
var taxRate1 = parseFloat(self.tax_rate1());
|
|
|
|
var tax1 = roundToTwo(total * (taxRate1/100));
|
|
|
|
|
|
|
|
var taxRate2 = parseFloat(self.tax_rate2());
|
|
|
|
var tax2 = roundToTwo(total * (taxRate2/100));
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-03-31 11:29:01 +02:00
|
|
|
return self.formatMoney(tax1 + tax2);
|
2015-10-22 20:48:12 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.itemTaxes = ko.computed(function() {
|
|
|
|
var taxes = {};
|
|
|
|
var total = self.totals.rawSubtotal();
|
|
|
|
for(var i=0; i<self.invoice_items().length; i++) {
|
|
|
|
var item = self.invoice_items()[i];
|
|
|
|
var lineTotal = item.totals.rawTotal();
|
|
|
|
if (self.discount()) {
|
|
|
|
if (parseInt(self.is_amount_discount())) {
|
|
|
|
lineTotal -= roundToTwo((lineTotal/total) * self.discount());
|
|
|
|
} else {
|
|
|
|
lineTotal -= roundToTwo(lineTotal * (self.discount()/100));
|
|
|
|
}
|
|
|
|
}
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-03-31 11:29:01 +02:00
|
|
|
var taxAmount = roundToTwo(lineTotal * item.tax_rate1() / 100);
|
2015-10-22 20:48:12 +02:00
|
|
|
if (taxAmount) {
|
2016-03-31 11:29:01 +02:00
|
|
|
var key = item.tax_name1() + item.tax_rate1();
|
2015-10-22 20:48:12 +02:00
|
|
|
if (taxes.hasOwnProperty(key)) {
|
|
|
|
taxes[key].amount += taxAmount;
|
|
|
|
} else {
|
2016-03-31 11:29:01 +02:00
|
|
|
taxes[key] = {name:item.tax_name1(), rate:item.tax_rate1(), amount:taxAmount};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var taxAmount = roundToTwo(lineTotal * item.tax_rate2() / 100);
|
|
|
|
if (taxAmount) {
|
|
|
|
var key = item.tax_name2() + item.tax_rate2();
|
|
|
|
if (taxes.hasOwnProperty(key)) {
|
|
|
|
taxes[key].amount += taxAmount;
|
|
|
|
} else {
|
|
|
|
taxes[key] = {name:item.tax_name2(), rate:item.tax_rate2(), amount:taxAmount};
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
2016-01-10 11:25:05 +01:00
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
return taxes;
|
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.hasItemTaxes = ko.computed(function() {
|
|
|
|
var count = 0;
|
|
|
|
var taxes = self.totals.itemTaxes();
|
|
|
|
for (var key in taxes) {
|
|
|
|
if (taxes.hasOwnProperty(key)) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count > 0;
|
|
|
|
});
|
|
|
|
|
2016-01-10 11:25:05 +01:00
|
|
|
self.totals.itemTaxRates = ko.computed(function() {
|
2015-10-22 20:48:12 +02:00
|
|
|
var taxes = self.totals.itemTaxes();
|
2016-01-10 11:25:05 +01:00
|
|
|
var parts = [];
|
2015-10-22 20:48:12 +02:00
|
|
|
for (var key in taxes) {
|
|
|
|
if (taxes.hasOwnProperty(key)) {
|
|
|
|
parts.push(taxes[key].name + ' ' + (taxes[key].rate*1) + '%');
|
2016-01-10 11:25:05 +01:00
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
return parts.join('<br/>');
|
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.itemTaxAmounts = ko.computed(function() {
|
|
|
|
var taxes = self.totals.itemTaxes();
|
2016-01-10 11:25:05 +01:00
|
|
|
var parts = [];
|
2015-10-22 20:48:12 +02:00
|
|
|
for (var key in taxes) {
|
|
|
|
if (taxes.hasOwnProperty(key)) {
|
2015-12-07 14:34:55 +01:00
|
|
|
parts.push(self.formatMoney(taxes[key].amount));
|
2016-01-10 11:25:05 +01:00
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
return parts.join('<br/>');
|
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.rawPaidToDate = ko.computed(function() {
|
2016-04-26 11:41:34 +02:00
|
|
|
return roundToTwo(accounting.toFixed(self.amount(),2) - accounting.toFixed(self.balance(),2));
|
2015-10-22 20:48:12 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.paidToDate = ko.computed(function() {
|
|
|
|
var total = self.totals.rawPaidToDate();
|
2015-12-07 14:34:55 +01:00
|
|
|
return self.formatMoney(total);
|
2015-10-22 20:48:12 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.rawTotal = ko.computed(function() {
|
2016-01-10 11:25:05 +01:00
|
|
|
var total = accounting.toFixed(self.totals.rawSubtotal(),2);
|
2015-10-22 20:48:12 +02:00
|
|
|
var discount = self.totals.rawDiscounted();
|
|
|
|
total -= discount;
|
|
|
|
|
|
|
|
var customValue1 = roundToTwo(self.custom_value1());
|
|
|
|
var customValue2 = roundToTwo(self.custom_value2());
|
|
|
|
var customTaxes1 = self.custom_taxes1() == 1;
|
|
|
|
var customTaxes2 = self.custom_taxes2() == 1;
|
|
|
|
|
|
|
|
if (customValue1 && customTaxes1) {
|
|
|
|
total = NINJA.parseFloat(total) + customValue1;
|
|
|
|
}
|
|
|
|
if (customValue2 && customTaxes2) {
|
|
|
|
total = NINJA.parseFloat(total) + customValue2;
|
|
|
|
}
|
|
|
|
|
2016-03-31 11:29:01 +02:00
|
|
|
var taxAmount1 = roundToTwo(total * (parseFloat(self.tax_rate1())/100));
|
|
|
|
var taxAmount2 = roundToTwo(total * (parseFloat(self.tax_rate2())/100));
|
|
|
|
total = NINJA.parseFloat(total) + taxAmount1 + taxAmount2;
|
2016-01-28 13:04:55 +01:00
|
|
|
total = roundToTwo(total);
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
var taxes = self.totals.itemTaxes();
|
|
|
|
for (var key in taxes) {
|
|
|
|
if (taxes.hasOwnProperty(key)) {
|
|
|
|
total += taxes[key].amount;
|
2016-07-11 19:08:43 +02:00
|
|
|
total = roundToTwo(total);
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (customValue1 && !customTaxes1) {
|
|
|
|
total = NINJA.parseFloat(total) + customValue1;
|
|
|
|
}
|
|
|
|
if (customValue2 && !customTaxes2) {
|
|
|
|
total = NINJA.parseFloat(total) + customValue2;
|
|
|
|
}
|
|
|
|
|
|
|
|
var paid = self.totals.rawPaidToDate();
|
|
|
|
if (paid > 0) {
|
|
|
|
total -= paid;
|
|
|
|
}
|
|
|
|
|
|
|
|
return total;
|
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.total = ko.computed(function() {
|
2016-03-18 13:34:46 +01:00
|
|
|
return self.formatMoney(self.totals.rawTotal());
|
|
|
|
});
|
|
|
|
|
|
|
|
self.totals.partial = ko.computed(function() {
|
|
|
|
return self.formatMoney(self.partial());
|
2016-01-10 11:25:05 +01:00
|
|
|
});
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
self.onDragged = function(item) {
|
|
|
|
refreshPDF(true);
|
|
|
|
}
|
2015-11-11 13:17:58 +01:00
|
|
|
|
|
|
|
self.showResetTerms = function() {
|
2016-07-28 18:55:23 +02:00
|
|
|
return self.default_terms() && self.terms() && self.terms() != self.default_terms();
|
2015-11-11 13:17:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
self.showResetFooter = function() {
|
2016-07-28 18:55:23 +02:00
|
|
|
return self.default_footer() && self.invoice_footer() && self.invoice_footer() != self.default_footer();
|
2015-11-11 13:17:58 +01:00
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function ClientModel(data) {
|
|
|
|
var self = this;
|
|
|
|
self.public_id = ko.observable(0);
|
|
|
|
self.name = ko.observable('');
|
|
|
|
self.id_number = ko.observable('');
|
|
|
|
self.vat_number = ko.observable('');
|
|
|
|
self.work_phone = ko.observable('');
|
|
|
|
self.custom_value1 = ko.observable('');
|
|
|
|
self.custom_value2 = ko.observable('');
|
|
|
|
self.private_notes = ko.observable('');
|
|
|
|
self.address1 = ko.observable('');
|
|
|
|
self.address2 = ko.observable('');
|
|
|
|
self.city = ko.observable('');
|
|
|
|
self.state = ko.observable('');
|
|
|
|
self.postal_code = ko.observable('');
|
|
|
|
self.country_id = ko.observable('');
|
|
|
|
self.size_id = ko.observable('');
|
|
|
|
self.industry_id = ko.observable('');
|
|
|
|
self.currency_id = ko.observable('');
|
|
|
|
self.language_id = ko.observable('');
|
|
|
|
self.website = ko.observable('');
|
|
|
|
self.payment_terms = ko.observable(0);
|
|
|
|
self.contacts = ko.observableArray();
|
|
|
|
|
|
|
|
self.mapping = {
|
|
|
|
'contacts': {
|
|
|
|
create: function(options) {
|
|
|
|
var model = new ContactModel(options.data);
|
|
|
|
model.send_invoice(options.data.send_invoice == '1');
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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.addContact = function() {
|
|
|
|
var contact = new ContactModel();
|
|
|
|
contact.send_invoice(true);
|
|
|
|
self.contacts.push(contact);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.removeContact = function() {
|
2016-01-10 11:25:05 +01:00
|
|
|
self.contacts.remove(this);
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
self.name.display = ko.computed(function() {
|
|
|
|
if (self.name()) {
|
|
|
|
return self.name();
|
|
|
|
}
|
|
|
|
if (self.contacts().length == 0) return;
|
2016-01-10 11:25:05 +01:00
|
|
|
var contact = self.contacts()[0];
|
2015-10-22 20:48:12 +02:00
|
|
|
if (contact.first_name() || contact.last_name()) {
|
2016-01-10 11:25:05 +01:00
|
|
|
return contact.first_name() + ' ' + contact.last_name();
|
2015-10-22 20:48:12 +02:00
|
|
|
} else {
|
|
|
|
return contact.email();
|
|
|
|
}
|
2016-01-10 11:25:05 +01:00
|
|
|
});
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
self.name.placeholder = ko.computed(function() {
|
|
|
|
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();
|
|
|
|
}
|
2016-01-10 11:25:05 +01:00
|
|
|
});
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
if (data) {
|
|
|
|
ko.mapping.fromJS(data, {}, this);
|
|
|
|
} else {
|
|
|
|
self.addContact();
|
2016-01-10 11:25:05 +01:00
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function ContactModel(data) {
|
|
|
|
var self = this;
|
|
|
|
self.public_id = ko.observable('');
|
|
|
|
self.first_name = ko.observable('');
|
|
|
|
self.last_name = ko.observable('');
|
|
|
|
self.email = ko.observable('');
|
2016-01-10 11:25:05 +01:00
|
|
|
self.phone = ko.observable('');
|
2015-10-22 20:48:12 +02:00
|
|
|
self.send_invoice = ko.observable(false);
|
|
|
|
self.invitation_link = ko.observable('');
|
|
|
|
self.invitation_status = ko.observable('');
|
2016-04-09 22:36:32 +02:00
|
|
|
self.invitation_openend = ko.observable(false);
|
2015-10-22 20:48:12 +02:00
|
|
|
self.invitation_viewed = ko.observable(false);
|
|
|
|
self.email_error = ko.observable('');
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
ko.mapping.fromJS(data, {}, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.displayName = ko.computed(function() {
|
|
|
|
var str = '';
|
|
|
|
if (self.first_name() || self.last_name()) {
|
2016-02-16 16:30:09 +01:00
|
|
|
str += (self.first_name() || '') + ' ' + (self.last_name() || '') + '\n';
|
2016-01-10 11:25:05 +01:00
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
if (self.email()) {
|
|
|
|
str += self.email() + '\n';
|
2016-01-10 11:25:05 +01:00
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
return str;
|
|
|
|
});
|
|
|
|
|
|
|
|
self.email.display = ko.computed(function() {
|
|
|
|
var str = '';
|
2016-02-16 16:30:09 +01:00
|
|
|
|
2015-10-22 20:48:12 +02:00
|
|
|
if (self.first_name() || self.last_name()) {
|
2016-02-16 16:30:09 +01:00
|
|
|
str += (self.first_name() || '') + ' ' + (self.last_name() || '') + '<br/>';
|
2016-01-10 11:25:05 +01:00
|
|
|
}
|
2015-10-22 20:48:12 +02:00
|
|
|
if (self.email()) {
|
2016-01-10 11:25:05 +01:00
|
|
|
str += self.email() + '<br/>';
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
return str;
|
|
|
|
});
|
|
|
|
|
|
|
|
self.view_as_recipient = ko.computed(function() {
|
|
|
|
var str = '';
|
|
|
|
@if (Utils::isConfirmed())
|
|
|
|
if (self.invitation_link()) {
|
|
|
|
str += '<a href="' + self.invitation_link() + '" target="_blank">{{ trans('texts.view_as_recipient') }}</a>';
|
|
|
|
}
|
|
|
|
@endif
|
|
|
|
|
|
|
|
return str;
|
2016-01-10 11:25:05 +01:00
|
|
|
});
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-04-09 22:36:32 +02:00
|
|
|
self.info_color = ko.computed(function() {
|
|
|
|
if (self.invitation_viewed()) {
|
|
|
|
return '#57D172';
|
|
|
|
} else if (self.invitation_openend()) {
|
2016-05-22 18:51:09 +02:00
|
|
|
return '#FFCC00';
|
2016-04-09 22:36:32 +02:00
|
|
|
} else {
|
|
|
|
return '#B1B5BA';
|
|
|
|
}
|
|
|
|
});
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function ItemModel(data) {
|
2016-01-10 11:25:05 +01:00
|
|
|
var self = this;
|
2015-10-22 20:48:12 +02:00
|
|
|
self.product_key = ko.observable('');
|
|
|
|
self.notes = ko.observable('');
|
|
|
|
self.cost = ko.observable(0);
|
|
|
|
self.qty = ko.observable(0);
|
2016-02-28 12:59:52 +01:00
|
|
|
self.custom_value1 = ko.observable('');
|
|
|
|
self.custom_value2 = ko.observable('');
|
2016-03-31 11:29:01 +02:00
|
|
|
self.tax_name1 = ko.observable('');
|
|
|
|
self.tax_rate1 = ko.observable(0);
|
|
|
|
self.tax_name2 = ko.observable('');
|
|
|
|
self.tax_rate2 = ko.observable(0);
|
2015-10-22 20:48:12 +02:00
|
|
|
self.task_public_id = ko.observable('');
|
2016-01-10 11:25:05 +01:00
|
|
|
self.expense_public_id = ko.observable('');
|
2015-10-22 20:48:12 +02:00
|
|
|
self.actionsVisible = ko.observable(false);
|
|
|
|
|
2016-03-31 11:29:01 +02:00
|
|
|
this.tax1 = ko.computed({
|
|
|
|
read: function () {
|
|
|
|
return self.tax_rate1() + ' ' + self.tax_name1();
|
|
|
|
},
|
|
|
|
write: function(value) {
|
|
|
|
var rate = value.substr(0, value.indexOf(' '));
|
|
|
|
var name = value.substr(value.indexOf(' ') + 1);
|
|
|
|
self.tax_name1(name);
|
|
|
|
self.tax_rate1(rate);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
this.tax2 = ko.computed({
|
2015-10-22 20:48:12 +02:00
|
|
|
read: function () {
|
2016-03-31 11:29:01 +02:00
|
|
|
return self.tax_rate2() + ' ' + self.tax_name2();
|
2015-10-22 20:48:12 +02:00
|
|
|
},
|
|
|
|
write: function(value) {
|
2016-03-27 17:06:02 +02:00
|
|
|
var rate = value.substr(0, value.indexOf(' '));
|
|
|
|
var name = value.substr(value.indexOf(' ') + 1);
|
2016-03-31 11:29:01 +02:00
|
|
|
self.tax_name2(name);
|
|
|
|
self.tax_rate2(rate);
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
this.prettyQty = ko.computed({
|
|
|
|
read: function () {
|
|
|
|
return NINJA.parseFloat(this.qty()) ? NINJA.parseFloat(this.qty()) : '';
|
|
|
|
},
|
|
|
|
write: function (value) {
|
|
|
|
this.qty(value);
|
|
|
|
},
|
|
|
|
owner: this
|
2016-01-10 11:25:05 +01:00
|
|
|
});
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
this.prettyCost = ko.computed({
|
|
|
|
read: function () {
|
|
|
|
return this.cost() ? this.cost() : '';
|
|
|
|
},
|
|
|
|
write: function (value) {
|
|
|
|
this.cost(value);
|
|
|
|
},
|
|
|
|
owner: this
|
2016-01-10 11:25:05 +01:00
|
|
|
});
|
2015-10-22 20:48:12 +02:00
|
|
|
|
|
|
|
if (data) {
|
2016-03-27 17:06:02 +02:00
|
|
|
ko.mapping.fromJS(data, {}, this);
|
2015-10-22 20:48:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
this.totals = ko.observable();
|
|
|
|
|
|
|
|
this.totals.rawTotal = ko.computed(function() {
|
|
|
|
var cost = roundToTwo(NINJA.parseFloat(self.cost()));
|
|
|
|
var qty = roundToTwo(NINJA.parseFloat(self.qty()));
|
2016-01-10 11:25:05 +01:00
|
|
|
var value = cost * qty;
|
2015-10-22 20:48:12 +02:00
|
|
|
return value ? roundToTwo(value) : 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
this.totals.total = ko.computed(function() {
|
|
|
|
var total = self.totals.rawTotal();
|
2016-02-16 22:56:59 +01:00
|
|
|
return window.hasOwnProperty('model') && total ? model.invoice().formatMoney(total) : '';
|
2015-10-22 20:48:12 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
this.hideActions = function() {
|
|
|
|
this.actionsVisible(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.showActions = function() {
|
|
|
|
this.actionsVisible(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.isEmpty = function() {
|
|
|
|
return !self.product_key() && !self.notes() && !self.cost() && (!self.qty() || {{ $account->hide_quantity ? 'true' : 'false' }});
|
|
|
|
}
|
|
|
|
|
|
|
|
this.onSelect = function() {}
|
|
|
|
}
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-03-23 03:23:45 +01:00
|
|
|
function DocumentModel(data) {
|
|
|
|
var self = this;
|
|
|
|
self.public_id = ko.observable(0);
|
|
|
|
self.size = ko.observable(0);
|
|
|
|
self.name = ko.observable('');
|
|
|
|
self.type = ko.observable('');
|
|
|
|
self.url = ko.observable('');
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-03-23 03:23:45 +01:00
|
|
|
self.update = function(data){
|
|
|
|
ko.mapping.fromJS(data, {}, this);
|
|
|
|
}
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-03-23 03:23:45 +01:00
|
|
|
if (data) {
|
|
|
|
self.update(data);
|
2016-05-22 18:51:09 +02:00
|
|
|
}
|
2016-03-23 03:23:45 +01:00
|
|
|
}
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-07-07 10:03:43 +02:00
|
|
|
function CategoryModel(data) {
|
|
|
|
var self = this;
|
|
|
|
self.name = ko.observable('')
|
|
|
|
|
|
|
|
self.update = function(data){
|
|
|
|
ko.mapping.fromJS(data, {}, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
self.update(data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-24 23:15:52 +01:00
|
|
|
var ExpenseModel = function(data) {
|
|
|
|
var self = this;
|
|
|
|
|
|
|
|
self.mapping = {
|
|
|
|
'documents': {
|
|
|
|
create: function(options) {
|
|
|
|
return new DocumentModel(options.data);
|
|
|
|
}
|
2016-07-07 10:03:43 +02:00
|
|
|
},
|
|
|
|
'expense_category': {
|
|
|
|
create: function(options) {
|
|
|
|
return new CategoryModel(options.data);
|
|
|
|
}
|
2016-03-24 23:15:52 +01:00
|
|
|
}
|
|
|
|
}
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-03-24 23:15:52 +01:00
|
|
|
self.description = ko.observable('');
|
|
|
|
self.qty = ko.observable(0);
|
|
|
|
self.public_id = ko.observable(0);
|
|
|
|
self.amount = ko.observable();
|
|
|
|
self.converted_amount = ko.observable();
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
ko.mapping.fromJS(data, self.mapping, this);
|
|
|
|
}
|
|
|
|
};
|
2015-10-22 20:48:12 +02:00
|
|
|
|
2016-02-29 10:40:52 +01:00
|
|
|
/* Custom binding for product key typeahead */
|
2016-07-05 20:49:47 +02:00
|
|
|
ko.bindingHandlers.productTypeahead = {
|
2016-02-29 10:40:52 +01:00
|
|
|
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
|
|
|
|
var $element = $(element);
|
|
|
|
var allBindings = allBindingsAccessor();
|
2016-05-22 18:51:09 +02:00
|
|
|
|
2016-02-29 10:40:52 +01:00
|
|
|
$element.typeahead({
|
|
|
|
highlight: true,
|
|
|
|
minLength: 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'data',
|
|
|
|
display: allBindings.key,
|
2016-04-11 12:30:23 +02:00
|
|
|
limit: 50,
|
2016-02-29 10:40:52 +01:00
|
|
|
source: searchData(allBindings.items, allBindings.key)
|
|
|
|
}).on('typeahead:select', function(element, datum, name) {
|
|
|
|
@if (Auth::user()->account->fill_products)
|
|
|
|
var model = ko.dataFor(this);
|
|
|
|
if (model.expense_public_id()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (datum.notes) {
|
|
|
|
model.notes(datum.notes);
|
|
|
|
}
|
|
|
|
if (datum.cost) {
|
|
|
|
model.cost(accounting.toFixed(datum.cost, 2));
|
|
|
|
}
|
|
|
|
if (!model.qty()) {
|
|
|
|
model.qty(1);
|
|
|
|
}
|
|
|
|
@if ($account->invoice_item_taxes)
|
|
|
|
if (datum.default_tax_rate) {
|
2016-03-31 11:29:01 +02:00
|
|
|
model.tax_rate1(datum.default_tax_rate.rate);
|
|
|
|
model.tax_name1(datum.default_tax_rate.name);
|
|
|
|
model.tax1(datum.default_tax_rate.rate + ' ' + datum.default_tax_rate.name);
|
2016-02-29 10:40:52 +01:00
|
|
|
}
|
|
|
|
@endif
|
|
|
|
@endif
|
|
|
|
onItemChange();
|
|
|
|
}).on('typeahead:change', function(element, datum, name) {
|
|
|
|
var value = valueAccessor();
|
|
|
|
value(datum);
|
|
|
|
onItemChange();
|
|
|
|
refreshPDF(true);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
update: function (element, valueAccessor) {
|
|
|
|
var value = ko.utils.unwrapObservable(valueAccessor());
|
|
|
|
if (value) {
|
|
|
|
$(element).typeahead('val', value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-07-27 14:46:05 +02:00
|
|
|
function checkInvoiceNumber() {
|
2016-09-25 19:36:15 +02:00
|
|
|
var url = '{{ url('check_invoice_number') }}/{{ $invoice->exists ? $invoice->public_id : '' }}?invoice_number=' + encodeURIComponent($('#invoice_number').val());
|
2016-07-27 14:46:05 +02:00
|
|
|
$.get(url, function(data) {
|
|
|
|
var isValid = data == '{{ RESULT_SUCCESS }}' ? true : false;
|
|
|
|
if (isValid) {
|
|
|
|
$('.invoice-number')
|
|
|
|
.removeClass('has-error')
|
|
|
|
.find('span')
|
|
|
|
.hide();
|
|
|
|
} else {
|
|
|
|
if ($('.invoice-number').hasClass('has-error')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
$('.invoice-number')
|
|
|
|
.addClass('has-error')
|
|
|
|
.find('div')
|
|
|
|
.append('<span class="help-block">{{ trans('validation.unique', ['attribute' => trans('texts.invoice_number')]) }}</span>');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-05-22 18:51:09 +02:00
|
|
|
</script>
|