Fix invoice item drag/drop sorting

This commit is contained in:
Hillel Coren 2017-07-27 10:18:43 +03:00
parent b8138288d5
commit cb09c9d5ae
3 changed files with 57 additions and 44 deletions

View File

@ -858,19 +858,14 @@
@endif @endif
@if (isset($tasks) && $tasks) @if (isset($tasks) && $tasks)
// move the blank invoice line item to the end
var blank = model.invoice().invoice_items.pop();
var tasks = {!! json_encode($tasks) !!}; var tasks = {!! json_encode($tasks) !!};
for (var i=0; i<tasks.length; i++) { for (var i=0; i<tasks.length; i++) {
var task = tasks[i]; var task = tasks[i];
var item = model.invoice().addItem(); var item = model.invoice().addItem(true);
item.notes(task.description); item.notes(task.description);
item.qty(task.duration); item.qty(task.duration);
item.task_public_id(task.publicId); item.task_public_id(task.publicId);
item.invoice_item_type_id({{ INVOICE_ITEM_TYPE_TASK }});
} }
model.invoice().invoice_items.push(blank);
model.invoice().has_tasks(true); model.invoice().has_tasks(true);
@endif @endif
@ -878,7 +873,7 @@
model.expense_currency_id({{ isset($expenseCurrencyId) ? $expenseCurrencyId : 0 }}); model.expense_currency_id({{ isset($expenseCurrencyId) ? $expenseCurrencyId : 0 }});
// move the blank invoice line item to the end // move the blank invoice line item to the end
var blank = model.invoice().invoice_items.pop(); var blank = model.invoice().invoice_items_without_tasks.pop();
var expenses = {!! $expenses !!} var expenses = {!! $expenses !!}
for (var i=0; i<expenses.length; i++) { for (var i=0; i<expenses.length; i++) {
@ -894,7 +889,7 @@
item.tax_rate2(expense.tax_rate2); item.tax_rate2(expense.tax_rate2);
item.tax_name2(expense.tax_name2); item.tax_name2(expense.tax_name2);
} }
model.invoice().invoice_items.push(blank); model.invoice().invoice_items_without_tasks.push(blank);
model.invoice().has_expenses(true); model.invoice().has_expenses(true);
@endif @endif
@ -1552,23 +1547,25 @@
{ {
var hasEmptyStandard = false; var hasEmptyStandard = false;
var hasEmptyTask = false; var hasEmptyTask = false;
for(var i=0; i<model.invoice().invoice_items().length; i++) {
var item = model.invoice().invoice_items()[i]; for (var i=0; i<model.invoice().invoice_items_without_tasks().length; i++) {
var item = model.invoice().invoice_items_without_tasks()[i];
if (item.isEmpty()) { if (item.isEmpty()) {
if (item.invoice_item_type_id() == {{ INVOICE_ITEM_TYPE_TASK }}) { hasEmptyStandard = true;
hasEmptyTask = true;
} else {
hasEmptyStandard = true;
}
} }
} }
if (!hasEmptyStandard) { if (!hasEmptyStandard) {
model.invoice().addItem(); model.invoice().addItem();
} }
for (var i=0; i<model.invoice().invoice_items_with_tasks().length; i++) {
var item = model.invoice().invoice_items_with_tasks()[i];
if (item.isEmpty()) {
hasEmptyTask = true;
}
}
if (!hasEmptyTask) { if (!hasEmptyTask) {
item = model.invoice().addItem(); model.invoice().addItem(true);
item.invoice_item_type_id({{ INVOICE_ITEM_TYPE_TASK }});
} }
if (!silent) { if (!silent) {

View File

@ -19,12 +19,12 @@
<th style="min-width:32px;" class="hide-border"></th> <th style="min-width:32px;" class="hide-border"></th>
</tr> </tr>
</thead> </thead>
<tbody data-bind="sortable: { data: {{ $isTasks ? 'invoice_items_with_tasks' : 'invoice_items_without_tasks' }}, afterMove: onDragged} {{ $isTasks ? ', visible: $root.hasTasks' : '' }}" <tbody data-bind="sortable: { data: invoice_items_{{ $isTasks ? 'with_tasks' : 'without_tasks' }}, allowDrop: false, afterMove: onDragged} {{ $isTasks ? ', visible: $root.hasTasks' : '' }}"
{!! $isTasks ? 'style="display:none;border-spacing: 100px"' : '' !!}> {!! $isTasks ? 'style="display:none;border-spacing: 100px"' : '' !!}>
<tr data-bind="event: { mouseover: showActions, mouseout: hideActions }" class="sortable-row"> <tr data-bind="event: { mouseover: showActions, mouseout: hideActions }" class="sortable-row">
<td class="hide-border td-icon"> <td class="hide-border td-icon">
<i style="display:none" data-bind="visible: actionsVisible() &amp;&amp; <i style="display:none" data-bind="visible: actionsVisible() &amp;&amp;
$parent.invoice_items().length > 1" class="fa fa-sort"></i> $parent.invoice_items_{{ $isTasks ? 'with_tasks' : 'without_tasks' }}().length > 1" class="fa fa-sort"></i>
</td> </td>
<td> <td>
<div id="scrollable-dropdown-menu"> <div id="scrollable-dropdown-menu">

View File

@ -166,15 +166,15 @@ function ViewModel(data) {
} }
}); });
self.hasTasksCached; self.hasTasksCached = false;
self.hasTasks = ko.computed(function() { self.hasTasks = ko.computed(function() {
if (self.hasTasksCached) { if (self.hasTasksCached) {
return true; return true;
} }
invoice = self.invoice(); invoice = self.invoice();
for (var i=0; i<invoice.invoice_items().length; ++i) { for (var i=0; i<invoice.invoice_items_with_tasks().length; ++i) {
var item = invoice.invoice_items()[i]; var item = invoice.invoice_items()[i];
if (! item.isEmpty() && item.invoice_item_type_id() == {{ INVOICE_ITEM_TYPE_TASK }}) { if (! item.isEmpty()) {
self.hasTasksCached = true; self.hasTasksCached = true;
return true; return true;
} }
@ -229,7 +229,6 @@ function InvoiceModel(data) {
self.auto_bill = ko.observable(0); self.auto_bill = ko.observable(0);
self.client_enable_auto_bill = ko.observable(false); self.client_enable_auto_bill = ko.observable(false);
self.invoice_status_id = ko.observable(0); self.invoice_status_id = ko.observable(0);
self.invoice_items = ko.observableArray();
self.documents = ko.observableArray(); self.documents = ko.observableArray();
self.expenses = ko.observableArray(); self.expenses = ko.observableArray();
self.amount = ko.observable(0); self.amount = ko.observable(0);
@ -246,17 +245,33 @@ function InvoiceModel(data) {
self.custom_text_value1 = ko.observable(); self.custom_text_value1 = ko.observable();
self.custom_text_value2 = ko.observable(); self.custom_text_value2 = ko.observable();
self.invoice_items_with_tasks = ko.observableArray();
self.invoice_items_without_tasks = ko.observableArray();
self.invoice_items = ko.computed({
read: function () {
return self.invoice_items_with_tasks().concat(self.invoice_items_without_tasks());
},
write: function(data) {
self.invoice_items_with_tasks.removeAll();
self.invoice_items_without_tasks.removeAll();
for (var i=0; i<data.length; i++) {
var item = new ItemModel(data[i]);
if (item.isTask()) {
self.invoice_items_with_tasks.push(item);
} else {
self.invoice_items_without_tasks.push(item);
}
}
},
owner: this
})
self.mapping = { self.mapping = {
'client': { 'client': {
create: function(options) { create: function(options) {
return new ClientModel(options.data); return new ClientModel(options.data);
} }
}, },
'invoice_items': {
create: function(options) {
return new ItemModel(options.data);
}
},
'documents': { 'documents': {
create: function(options) { create: function(options) {
return new DocumentModel(options.data); return new DocumentModel(options.data);
@ -269,7 +284,7 @@ function InvoiceModel(data) {
}, },
} }
self.addItem = function() { self.addItem = function(isTask) {
if (self.invoice_items().length >= {{ MAX_INVOICE_ITEMS }}) { if (self.invoice_items().length >= {{ MAX_INVOICE_ITEMS }}) {
return false; return false;
} }
@ -277,7 +292,12 @@ function InvoiceModel(data) {
@if ($account->hide_quantity) @if ($account->hide_quantity)
itemModel.qty(1); itemModel.qty(1);
@endif @endif
self.invoice_items.push(itemModel); if (isTask) {
itemModel.invoice_item_type_id({{ INVOICE_ITEM_TYPE_TASK }});
self.invoice_items_with_tasks.push(itemModel);
} else {
self.invoice_items_without_tasks.push(itemModel);
}
applyComboboxListeners(); applyComboboxListeners();
return itemModel; return itemModel;
} }
@ -329,7 +349,11 @@ function InvoiceModel(data) {
}) })
self.removeItem = function(item) { self.removeItem = function(item) {
self.invoice_items.remove(item); if (item.isTask()) {
self.invoice_items_with_tasks.remove(item);
} else {
self.invoice_items_without_tasks.remove(item);
}
refreshPDF(true); refreshPDF(true);
} }
@ -568,18 +592,6 @@ function InvoiceModel(data) {
} }
self.applyInclusivTax(taxRate); self.applyInclusivTax(taxRate);
} }
self.invoice_items_with_tasks = ko.computed(function() {
return ko.utils.arrayFilter(self.invoice_items(), function(item) {
return item.invoice_item_type_id() == {{ INVOICE_ITEM_TYPE_TASK }};
});
});
self.invoice_items_without_tasks = ko.computed(function() {
return ko.utils.arrayFilter(self.invoice_items(), function(item) {
return item.invoice_item_type_id() != {{ INVOICE_ITEM_TYPE_TASK }};
});
});
} }
function ClientModel(data) { function ClientModel(data) {
@ -769,6 +781,10 @@ function ItemModel(data) {
self.invoice_item_type_id = ko.observable({{ INVOICE_ITEM_TYPE_STANDARD }}); self.invoice_item_type_id = ko.observable({{ INVOICE_ITEM_TYPE_STANDARD }});
self.actionsVisible = ko.observable(false); self.actionsVisible = ko.observable(false);
self.isTask = ko.computed(function() {
return self.invoice_item_type_id() == {{ INVOICE_ITEM_TYPE_TASK }};
});
this.tax1 = ko.computed({ this.tax1 = ko.computed({
read: function () { read: function () {
return self.tax_rate1IsInclusive() + ' ' + self.tax_rate1() + ' ' + self.tax_name1(); return self.tax_rate1IsInclusive() + ' ' + self.tax_rate1() + ' ' + self.tax_name1();