Browse Source

- Make search_query a property

- Fix search clear button

- Refactor load_order and actions

This refactors load_data into two functions: load_order_data and load_order_from_data.
Also, when executing actions, instead of sending the order as an argument, only the order_data will be sent.
The action method is responsible for generating the order data (if that's what it needs)

All the refund logic has been extracted from the various methods, and it's now in action_return.

Now, returns have a specific 'Refund XXXX' name.

- IMP Allow to duplicate done orders from the POS

- IMP filter by customer name, too, when searching
pull/378/head
Iván Todorovich 5 years ago
committed by OCA-git-bot
parent
commit
336c6a5383
  1. 3
      pos_order_mgmt/README.rst
  2. 8
      pos_order_mgmt/models/pos_config.py
  3. 7
      pos_order_mgmt/models/pos_order.py
  4. 1
      pos_order_mgmt/readme/CONTRIBUTORS.rst
  5. 190
      pos_order_mgmt/static/src/js/widgets.js
  6. 3
      pos_order_mgmt/static/src/xml/pos.xml
  7. 11
      pos_order_mgmt/views/view_pos_config.xml

3
pos_order_mgmt/README.rst

@ -106,7 +106,10 @@ Contributors
* David Vidal <david.vidal@tecnativa.com>
* Sylvain LE GAL (https://twitter.com/legalsylvain)
* Carlos Martínez <carlos@domatix.com>
* Pierrick Brun <pierrick.brun@akretion.com>
* Iván Todorovich <ivan.todorovich@druidoo.io>
Maintainers
~~~~~~~~~~~

8
pos_order_mgmt/models/pos_config.py

@ -16,12 +16,20 @@ class PosConfig(models.Model):
help='Allows to reprint already done orders in the frontend',
oldname='iface_load_done_order',
)
iface_return_done_order = fields.Boolean(
string='Return Done Orders',
default=True,
help='Allows to return already done orders in the frontend',
oldname='iface_load_done_order',
)
iface_copy_done_order = fields.Boolean(
string='Duplicate Done Orders',
default=True,
help='Allows to duplicate already done orders in the frontend',
)
iface_load_done_order_max_qty = fields.Integer(
string='Max. Done Orders Quantity To Load',
default=10,

7
pos_order_mgmt/models/pos_order.py

@ -33,9 +33,10 @@ class PosOrder(models.Model):
@api.model
def _prepare_filter_query_for_pos(self, pos_session_id, query):
return [
'|',
'|', '|',
('name', 'ilike', query),
('pos_reference', 'ilike', query),
('partner_id.display_name', 'ilike', query),
]
@api.model
@ -57,8 +58,8 @@ class PosOrder(models.Model):
condition += [('config_id', '=', config.id)]
else:
# Search globally by criteria
condition += self._prepare_filter_query_for_pos(pos_session_id,
query)
condition += self._prepare_filter_query_for_pos(
pos_session_id, query)
field_names = self._prepare_fields_for_pos_list()
return self.search_read(
condition, field_names, limit=config.iface_load_done_order_max_qty)

1
pos_order_mgmt/readme/CONTRIBUTORS.rst

@ -2,3 +2,4 @@
* Sylvain LE GAL (https://twitter.com/legalsylvain)
* Carlos Martínez <carlos@domatix.com>
* Pierrick Brun <pierrick.brun@akretion.com>
* Iván Todorovich <ivan.todorovich@druidoo.io>

190
pos_order_mgmt/static/src/js/widgets.js

@ -1,5 +1,6 @@
/* Copyright 2018 GRAP - Sylvain LE GAL
Copyright 2018 Tecnativa - David Vidal
Copyright 2019 Druidoo - Ivan Todorovich
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). */
odoo.define('pos_order_mgmt.widgets', function (require) {
"use strict";
@ -56,7 +57,8 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
this.order_cache = new DomCache();
this.orders = [];
this.unknown_products = [];
this.search_done_orders();
this.search_query = false;
this.perform_search();
},
auto_back: true,
@ -77,24 +79,25 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
this.$('.back').click(function () {
return self.gui.show_screen(self.gui.startup_screen);
});
if (self.orders.length === 0) {
this.search_done_orders();
}
this.render_list();
var search_timeout = null;
if (this.pos.config.iface_vkeyboard && this.chrome.widget.keyboard) {
this.chrome.widget.keyboard.connect(this.$('.searchbox input'));
}
var search_timeout = null;
this.$('.searchbox input').on('keyup', function (event) {
self.search_query = this.value;
clearTimeout(search_timeout);
var query = this.value;
search_timeout = setTimeout(function () {
self.perform_search(query, event.which === 13);
self.perform_search();
}, 70);
});
this.$('.searchbox .search-clear').click(function () {
self.clear_search();
});
this.perform_search();
},
render_list: function () {
@ -126,34 +129,46 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
// button events.
this.$('.order-list-return').off('click');
this.$('.order-list-reprint').off('click');
this.$('.order-list-copy').off('click');
this.$('.order-list-return').click(function (event) {
self.order_list_actions(event, 'return');
});
this.$('.order-list-reprint').click(function (event) {
self.order_list_actions(event, 'print');
});
this.$('.order-list-copy').click(function(event) {
self.order_list_actions(event, 'copy');
});
},
order_list_actions: function (event, action) {
var dataset = event.target.parentNode.dataset;
var self = this;
var order_data;
var dataset = event.target.parentNode.dataset;
if (dataset.orderId) {
this.load_order(parseInt(dataset.orderId, 10), action);
self.load_order_data(parseInt(dataset.orderId, 10))
.then(function(order_data) {
self.order_action(order_data, action);
})
} else {
var local_order = '';
_.each(this.orders, function (order) {
_.each(this.orders, function (order_data) {
if (order.uid === dataset.uid) {
order.return = action === 'return';
local_order = self._prepare_order_from_order_data(order);
self.order_action(order_data, action);
}
});
if (local_order) {
this['action_' + action](local_order);
}
}
},
action_print: function (order) {
order_action: function(order_data, action) {
this.gui.back();
this['action_' + action](order_data);
},
action_print: function (order_data) {
var order = this.load_order_from_data(order_data, true);
if (!order) return false;
// Restore the previous name
order.name = order_data.pos_reference || order_data.name;
var receipt = order.export_for_printing();
// We store temporarily the current order so we can safely compute
// taxes based on fiscal position
@ -178,26 +193,56 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
}
},
action_return: function (order) {
action_copy: function(order_data) {
// Remove payments from original data
order_data.statement_ids = false;
var order = this.load_order_from_data(order_data, true);
if (!order) { return false; }
// If previous order was invoiced, we need a refund too
order.set_to_invoice(order_data.origin_invoice_id);
order.formatted_validation_date = false;
order.trigger('change');
this.pos.get('orders').add(order);
this.pos.set('selectedOrder', order);
return order;
},
_prepare_order_from_order_data: function (order_data) {
action_return: function (order_data) {
//var order_data = _.cloneDeep(order_data);
// Remove payments from original data
order_data.statement_ids = false;
// Invert line quantities
var order_lines = order_data.line_ids || order_data.lines || [];
_.each(order_lines, function(line) { line.qty = -1 * line.qty })
// Load from new data and change some stuff
var order = this.load_order_from_data(order_data);
if (!order) { return false; }
order.return = true;
order.name = _t("Refund ") + order.uid;;
order.origin_name = order_data.pos_reference || order.returned_order_id;
// If previous order was invoiced, we need a refund too
order.set_to_invoice(order_data.origin_invoice_id);
order.formatted_validation_date = false;
order.trigger('change');
// Add to pos
this.pos.get('orders').add(order);
this.pos.set('selectedOrder', order);
return order;
},
_prepare_order_from_order_data: function (order_data, temporary) {
var self = this;
var order = new pos.Order({}, {
pos: this.pos,
temporary: !order_data.return,
temporary: !!temporary,
});
// Set Generic Info
if (!order_data.return) {
order.name = order_data.pos_reference || order_data.name;
}
if (order_data.partner_id.length) {
order_data.partner_id = order_data.partner_id[0];
}
order.set_client(this.pos.db.get_partner_by_id(order_data.partner_id));
// Set fiscal position
if (order_data.fiscal_position && this.pos.fiscal_positions) {
var fiscal_positions = this.pos.fiscal_positions;
@ -206,23 +251,17 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
})[0];
order.trigger('change');
}
// Set order lines
var orderLines = order_data.line_ids || order_data.lines || [];
self._prepare_orderlines_from_order_data(order, order_data, orderLines);
if (order_data.return) {
order.return = true;
// A credit note should be emited if there was an invoice
order.set_to_invoice(order_data.origin_invoice_id);
// We'll refunded orders once they are synced
order.returned_order_id = order_data.id || order_data.name;
order.origin_name = order_data.pos_reference || order.returned_order_id;
order.trigger('change');
return order;
}
if (order_data.returned_order_id) {
order.origin_name = order_data.returned_order_id;
}
order.formatted_validation_date = moment(order_data.date_order).format('YYYY-MM-DD HH:mm:ss');
// Set Payment lines
var paymentLines = order_data.statement_ids || [];
_.each(paymentLines, function (paymentLine) {
@ -243,6 +282,7 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
});
return order;
},
_prepare_orderlines_from_order_data: function(order, order_data, orderLines) {
var self = this;
_.each(orderLines, function(line) {
@ -258,7 +298,7 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
// Create a new order line
order.add_product(product, {
price: line.price_unit,
quantity: order_data.return ? line.qty * -1 : line.qty,
quantity: line.qty,
discount: line.discount,
merge: false,
});
@ -266,36 +306,12 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
});
},
load_order: function (order_id, action) {
this.unknown_products = [];
load_order_data: function(order_id) {
var self = this;
return this._rpc({
model: 'pos.order',
method: 'load_done_order_for_pos',
args: [order_id],
}).then(function (order_data) {
self.gui.back();
var correct_order_print = true;
if (action === 'return') {
order_data.return = true;
}
var order = self._prepare_order_from_order_data(order_data);
// Forbid POS Order loading if some products are unknown
if (self.unknown_products.length > 0) {
self.gui.show_popup('error-traceback', {
'title': _t('Unknown Products'),
'body': _t('Unable to load some order lines because the ' +
'products are not available in the POS cache.\n\n' +
'Please check that lines :\n\n * ') + self.unknown_products.join("; \n *"),
});
correct_order_print = false;
}
if (correct_order_print && action === 'print') {
self.action_print(order);
}
if (correct_order_print && action === 'return') {
self.action_return(order);
}
}).fail(function (error, event) {
if (parseInt(error.code, 10) === 200) {
// Business Logic Error, not a connection problem
@ -310,10 +326,42 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
'body': _t('Can not execute this action because the POS is currently offline'),
});
}
event.preventDefault();
});
},
load_order_from_data: function(order_data) {
var self = this;
this.unknown_products = [];
var order = self._prepare_order_from_order_data(order_data);
// Forbid POS Order loading if some products are unknown
if (self.unknown_products.length > 0) {
self.gui.show_popup('error-traceback', {
'title': _t('Unknown Products'),
'body': _t('Unable to load some order lines because the ' +
'products are not available in the POS cache.\n\n' +
'Please check that lines :\n\n * ') + self.unknown_products.join("; \n *"),
});
return false;
}
return order;
},
/* deprecated */
load_order: function (order_id) {
var self = this;
var done = new $.Deferred();
this.load_order_data(order_id)
.then(function(order_data) {
self.gui.show_screen('orderlist');
var order = self.load_order_from_data(order_data);
if (!order) { return done.fail(); }
done.resolve(order);
}).fail(function() {
done.fail();
});
return done;
},
// Search Part
search_done_orders: function (query) {
var self = this;
@ -342,22 +390,18 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
});
},
perform_search: function (query) {
perform_search: function() {
var self = this;
this.search_done_orders(query)
.done(function () {
self.render_list();
});
return this.search_done_orders(self.search_query)
.done(function () { self.render_list(); });
},
clear_search: function () {
var self = this;
this.search_done_orders()
.done(function () {
self.$('.searchbox input')[0].value = '';
self.$('.searchbox input').focus();
self.render_list();
});
self.$('.searchbox input')[0].value = '';
self.$('.searchbox input').focus();
self.search_query = false;
self.perform_search();
},
});

3
pos_order_mgmt/static/src/xml/pos.xml

@ -58,6 +58,9 @@
<span t-if="widget.pos.config.iface_reprint_done_order" class="button order-list-reprint" t-att-data-order-id="order.id" t-att-data-Uid='order.uid'>
<i class='fa fa-fw fa-print'/>
</span>
<span t-if="widget.pos.config.iface_copy_done_order" class="button order-list-copy" t-att-data-order-id="order.id" t-att-data-Uid='order.uid'>
<i class='fa fa-fw fa-copy'/>
</span>
<span t-if="widget.pos.config.iface_return_done_order and order.amount_total >= 0" class="button order-list-return" t-att-data-order-id="order.id" t-att-data-Uid='order.uid'>
<i class='fa fa-fw fa-undo'/>
</span>

11
pos_order_mgmt/views/view_pos_config.xml

@ -33,6 +33,17 @@
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box" id="copy_done_order">
<div class="o_setting_left_pane">
<field name="iface_copy_done_order"/>
</div>
<div class="o_setting_right_pane">
<label string="Duplicate Done Orders" for="iface_copy_done_order"/>
<div class="text-muted">
Allow to duplicate done orders in this POS
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box" id="load_done_order_max_qty"
attrs="{'invisible': [('iface_reprint_done_order', '=', False),
('iface_return_done_order', '=', False)]}">

Loading…
Cancel
Save