diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/pos_restaurant/static/src/js/floors.js | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (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.js | 399 |
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; + }, +}); + +}); |
