summaryrefslogtreecommitdiff
path: root/addons/pos_restaurant/static/src/js/floors.js
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/pos_restaurant/static/src/js/floors.js
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/pos_restaurant/static/src/js/floors.js')
-rw-r--r--addons/pos_restaurant/static/src/js/floors.js399
1 files changed, 399 insertions, 0 deletions
diff --git a/addons/pos_restaurant/static/src/js/floors.js b/addons/pos_restaurant/static/src/js/floors.js
new file mode 100644
index 00000000..3f5b739a
--- /dev/null
+++ b/addons/pos_restaurant/static/src/js/floors.js
@@ -0,0 +1,399 @@
+odoo.define('pos_restaurant.floors', function (require) {
+"use strict";
+
+var models = require('point_of_sale.models');
+const { Gui } = require('point_of_sale.Gui');
+const { posbus } = require('point_of_sale.utils');
+
+// At POS Startup, load the floors, and add them to the pos model
+models.load_models({
+ model: 'restaurant.floor',
+ fields: ['name','background_color','table_ids','sequence'],
+ domain: function(self){ return [['pos_config_id','=',self.config.id]]; },
+ loaded: function(self,floors){
+ self.floors = floors;
+ self.floors_by_id = {};
+ for (var i = 0; i < floors.length; i++) {
+ floors[i].tables = [];
+ self.floors_by_id[floors[i].id] = floors[i];
+ }
+
+ // Make sure they display in the correct order
+ self.floors = self.floors.sort(function(a,b){ return a.sequence - b.sequence; });
+
+ // Ignore floorplan features if no floor specified.
+ self.config.iface_floorplan = !!self.floors.length;
+ },
+});
+
+// At POS Startup, after the floors are loaded, load the tables, and associate
+// them with their floor.
+models.load_models({
+ model: 'restaurant.table',
+ fields: ['name','width','height','position_h','position_v','shape','floor_id','color','seats'],
+ loaded: function(self,tables){
+ self.tables_by_id = {};
+ for (var i = 0; i < tables.length; i++) {
+ self.tables_by_id[tables[i].id] = tables[i];
+ var floor = self.floors_by_id[tables[i].floor_id[0]];
+ if (floor) {
+ floor.tables.push(tables[i]);
+ tables[i].floor = floor;
+ }
+ }
+ },
+});
+
+// New orders are now associated with the current table, if any.
+var _super_order = models.Order.prototype;
+models.Order = models.Order.extend({
+ initialize: function(attr,options) {
+ _super_order.initialize.apply(this,arguments);
+ if (!this.table && !options.json) {
+ this.table = this.pos.table;
+ }
+ this.customer_count = this.customer_count || 1;
+ this.save_to_db();
+ },
+ export_as_JSON: function() {
+ var json = _super_order.export_as_JSON.apply(this,arguments);
+ json.table = this.table ? this.table.name : undefined;
+ json.table_id = this.table ? this.table.id : false;
+ json.floor = this.table ? this.table.floor.name : false;
+ json.floor_id = this.table ? this.table.floor.id : false;
+ json.customer_count = this.customer_count;
+ return json;
+ },
+ init_from_JSON: function(json) {
+ _super_order.init_from_JSON.apply(this,arguments);
+ this.table = this.pos.tables_by_id[json.table_id];
+ this.floor = this.table ? this.pos.floors_by_id[json.floor_id] : undefined;
+ this.customer_count = json.customer_count || 1;
+ },
+ export_for_printing: function() {
+ var json = _super_order.export_for_printing.apply(this,arguments);
+ json.table = this.table ? this.table.name : undefined;
+ json.floor = this.table ? this.table.floor.name : undefined;
+ json.customer_count = this.get_customer_count();
+ return json;
+ },
+ get_customer_count: function(){
+ return this.customer_count;
+ },
+ set_customer_count: function(count) {
+ this.customer_count = Math.max(count,0);
+ this.trigger('change');
+ },
+});
+
+// We need to change the way the regular UI sees the orders, it
+// needs to only see the orders associated with the current table,
+// and when an order is validated, it needs to go back to the floor map.
+//
+// And when we change the table, we must create an order for that table
+// if there is none.
+var _super_posmodel = models.PosModel.prototype;
+models.PosModel = models.PosModel.extend({
+ after_load_server_data: async function() {
+ var res = await _super_posmodel.after_load_server_data.call(this);
+ if (this.config.iface_floorplan) {
+ this.table = null;
+ }
+ return res;
+ },
+
+ transfer_order_to_different_table: function () {
+ this.order_to_transfer_to_different_table = this.get_order();
+
+ // go to 'floors' screen, this will set the order to null and
+ // eventually this will cause the gui to go to its
+ // default_screen, which is 'floors'
+ this.set_table(null);
+ },
+
+ remove_from_server_and_set_sync_state: function(ids_to_remove){
+ var self = this;
+ this.set_synch('connecting', ids_to_remove.length);
+ return self._remove_from_server(ids_to_remove)
+ .then(function(server_ids) {
+ self.set_synch('connected');
+ }).catch(function(reason){
+ self.set_synch('error');
+ throw reason;
+ });
+ },
+
+ /**
+ * Request the orders of the table with given id.
+ * @param {number} table_id.
+ * @param {dict} options.
+ * @param {number} options.timeout optional timeout parameter for the rpc call.
+ * @return {Promise}
+ */
+ _get_from_server: function (table_id, options) {
+ options = options || {};
+ var timeout = typeof options.timeout === 'number' ? options.timeout : 7500;
+ return this.rpc({
+ model: 'pos.order',
+ method: 'get_table_draft_orders',
+ args: [table_id],
+ kwargs: {context: this.session.user_context},
+ }, {
+ timeout: timeout,
+ shadow: false,
+ })
+ },
+
+ transfer_order_to_table: function(table) {
+ this.order_to_transfer_to_different_table.table = table;
+ this.order_to_transfer_to_different_table.save_to_db();
+ },
+
+ push_order_for_transfer: function(order_ids, table_orders) {
+ order_ids.push(this.order_to_transfer_to_different_table.uid);
+ table_orders.push(this.order_to_transfer_to_different_table);
+ },
+
+ clean_table_transfer: function(table) {
+ if (this.order_to_transfer_to_different_table && table) {
+ this.order_to_transfer_to_different_table = null;
+ this.set_table(table);
+ }
+ },
+
+ sync_from_server: function(table, table_orders, order_ids) {
+ var self = this;
+ var ids_to_remove = this.db.get_ids_to_remove_from_server();
+ var orders_to_sync = this.db.get_unpaid_orders_to_sync(order_ids);
+ if (orders_to_sync.length) {
+ this.set_synch('connecting', orders_to_sync.length);
+ this._save_to_server(orders_to_sync, {'draft': true}).then(function (server_ids) {
+ server_ids.forEach(server_id => self.update_table_order(server_id, table_orders));
+ if (!ids_to_remove.length) {
+ self.set_synch('connected');
+ } else {
+ self.remove_from_server_and_set_sync_state(ids_to_remove);
+ }
+ }).catch(function(reason){
+ self.set_synch('error');
+ }).finally(function(){
+ self.clean_table_transfer(table);
+ });
+ } else {
+ if (ids_to_remove.length) {
+ self.remove_from_server_and_set_sync_state(ids_to_remove);
+ }
+ self.clean_table_transfer(table);
+ }
+ },
+
+ update_table_order: function(server_id, table_orders) {
+ const order = table_orders.find(o => o.name === server_id.pos_reference);
+ if (order) {
+ order.server_id = server_id.id;
+ order.save_to_db();
+ }
+ return order;
+ },
+
+ /**
+ * @param {models.Order} order order to set
+ */
+ set_order_on_table: function(order) {
+ var orders = this.get_order_list();
+ if (orders.length) {
+ order = order ? orders.find((o) => o.uid === order.uid) : null;
+ if (order) {
+ this.set_order(order);
+ } else {
+ // do not mindlessly set the first order in the list.
+ orders = orders.filter(order => !order.finalized);
+ if (orders.length) {
+ this.set_order(orders[0]);
+ } else {
+ this.add_new_order();
+ }
+ }
+ } else {
+ this.add_new_order(); // or create a new order with the current table
+ }
+ },
+
+ sync_to_server: function(table, order) {
+ var self = this;
+ var ids_to_remove = this.db.get_ids_to_remove_from_server();
+
+ this.set_synch('connecting', 1);
+ this._get_from_server(table.id).then(function (server_orders) {
+ var orders = self.get_order_list();
+ orders.forEach(function(order){
+ // We don't remove the validated orders because we still want to see them
+ // in the ticket screen. Orders in 'ReceiptScreen' or 'TipScreen' are validated
+ // orders.
+ if (order.server_id && !order.finalized){
+ self.get("orders").remove(order);
+ order.destroy();
+ }
+ });
+ server_orders.forEach(function(server_order){
+ if (server_order.lines.length){
+ var new_order = new models.Order({},{pos: self, json: server_order});
+ self.get("orders").add(new_order);
+ new_order.save_to_db();
+ }
+ })
+ if (!ids_to_remove.length) {
+ self.set_synch('connected');
+ } else {
+ self.remove_from_server_and_set_sync_state(ids_to_remove);
+ }
+ }).catch(function(reason){
+ self.set_synch('error');
+ }).finally(function(){
+ self.set_order_on_table(order);
+ });
+ },
+
+ get_order_with_uid: function() {
+ var order_ids = [];
+ this.get_order_list().forEach(function(o){
+ order_ids.push(o.uid);
+ });
+
+ return order_ids;
+ },
+
+ /**
+ * Changes the current table.
+ *
+ * Switch table and make sure all nececery syncing tasks are done.
+ * @param {object} table.
+ * @param {models.Order|undefined} order if provided, set to this order
+ */
+ set_table: function(table, order) {
+ if(!table){
+ this.sync_from_server(table, this.get_order_list(), this.get_order_with_uid());
+ this.set_order(null);
+ this.table = null;
+ } else if (this.order_to_transfer_to_different_table) {
+ var order_ids = this.get_order_with_uid();
+
+ this.transfer_order_to_table(table);
+ this.push_order_for_transfer(order_ids, this.get_order_list());
+
+ this.sync_from_server(table, this.get_order_list(), order_ids);
+ this.set_order(null);
+ } else {
+ this.table = table;
+ this.sync_to_server(table, order);
+ }
+ posbus.trigger('table-set');
+ },
+
+ // if we have tables, we do not load a default order, as the default order will be
+ // set when the user selects a table.
+ set_start_order: function() {
+ if (!this.config.iface_floorplan) {
+ _super_posmodel.set_start_order.apply(this,arguments);
+ }
+ },
+
+ // we need to prevent the creation of orders when there is no
+ // table selected.
+ add_new_order: function() {
+ if (this.config.iface_floorplan) {
+ if (this.table) {
+ return _super_posmodel.add_new_order.apply(this, arguments);
+ } else {
+ Gui.showPopup('ConfirmPopup', {
+ title: 'Unable to create order',
+ body: 'Orders cannot be created when there is no active table in restaurant mode',
+ });
+ return undefined;
+ }
+ } else {
+ return _super_posmodel.add_new_order.apply(this,arguments);
+ }
+ },
+
+
+ // get the list of unpaid orders (associated to the current table)
+ get_order_list: function() {
+ var orders = _super_posmodel.get_order_list.call(this);
+ if (!(this.config && this.config.iface_floorplan)) {
+ return orders;
+ } else if (!this.table) {
+ return [];
+ } else {
+ var t_orders = [];
+ for (var i = 0; i < orders.length; i++) {
+ if ( orders[i].table === this.table) {
+ t_orders.push(orders[i]);
+ }
+ }
+ return t_orders;
+ }
+ },
+
+ // get the list of orders associated to a table. FIXME: should be O(1)
+ get_table_orders: function(table) {
+ var orders = _super_posmodel.get_order_list.call(this);
+ var t_orders = [];
+ for (var i = 0; i < orders.length; i++) {
+ if (orders[i].table === table) {
+ t_orders.push(orders[i]);
+ }
+ }
+ return t_orders;
+ },
+
+ // get customer count at table
+ get_customer_count: function(table) {
+ var orders = this.get_table_orders(table).filter(order => !order.finalized);
+ var count = 0;
+ for (var i = 0; i < orders.length; i++) {
+ count += orders[i].get_customer_count();
+ }
+ return count;
+ },
+
+ // When we validate an order we go back to the floor plan.
+ // When we cancel an order and there is multiple orders
+ // on the table, stay on the table.
+ on_removed_order: function(removed_order,index,reason){
+ if (this.config.iface_floorplan) {
+ var order_list = this.get_order_list();
+ if (reason === 'abandon') {
+ this.db.set_order_to_remove_from_server(removed_order);
+ }
+ if( (reason === 'abandon' || removed_order.temporary) && order_list.length > 0){
+ this.set_order(order_list[index] || order_list[order_list.length - 1], { silent: true });
+ } else if (order_list.length === 0) {
+ this.table ? this.set_order(null) : this.set_table(null);
+ }
+ } else {
+ _super_posmodel.on_removed_order.apply(this,arguments);
+ }
+ },
+
+
+});
+
+
+var _super_paymentline = models.Paymentline.prototype;
+models.Paymentline = models.Paymentline.extend({
+ /**
+ * Override this method to be able to show the 'Adjust Authorisation' button
+ * on a validated payment_line and to show the tip screen which allow
+ * tipping even after payment. By default, this returns true for all
+ * non-cash payment.
+ */
+ canBeAdjusted: function() {
+ if (this.payment_method.payment_terminal) {
+ return this.payment_method.payment_terminal.canBeAdjusted(this.cid);
+ }
+ return !this.payment_method.is_cash_count;
+ },
+});
+
+});