Ver código fonte

First commit

deisy 5 anos atrás
commit
bf6d8f1ff1

+ 49 - 0
README.rst

@@ -0,0 +1,49 @@
+.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
+   :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+   :alt: License: AGPL-3
+
+===========================================
+Point Of Sale - Restaurant Table Management
+===========================================
+
+Point Of Sale Restaurant Table Management
+
+Installation
+============
+
+To install this module, you need to:
+
+1.  Clone the branch 8.0 of the repository https://github.com/open-synergy/opnsynid-pos
+2.  Add the path to this repository in your configuration (addons-path)
+3.  Update the module list
+4.  Go to menu *Setting -> Modules -> Local Modules*
+5.  Search For *Point Of Sale - Restaurant Table Management*
+6.  Install the module
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues
+<https://github.com/open-synergy/opnsynid-pos/issues>`_.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed
+and welcomed feedback.
+
+
+Credits
+=======
+
+Contributors
+------------
+
+* Andhitia Rama <andhitia.r@gmail.com>
+* Michael Viriyananda <viriyananda.michael@gmail.com>
+
+Maintainer
+----------
+
+.. image:: https://opensynergy-indonesia.com/logo.png
+   :alt: OpenSynergy Indonesia
+   :target: https://opensynergy-indonesia.com
+
+This module is maintained by the OpenSynergy Indonesia.

+ 5 - 0
__init__.py

@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import models

+ 27 - 0
__openerp__.py

@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+{
+    "name": "Mesas y Delivery para Restaurantes",
+    "version": "8.0.1.0.0",
+    "website": "https://opensynergy-indonesia.com",
+    "author": "OpenSynergy Indonesia",
+    "license": "AGPL-3",
+    "installable": True,
+    "depends": [
+        "point_of_sale",
+        "pos_restaurant",
+        "hr",
+    ],
+    "data": [
+        "security/ir.model.access.csv",
+        "views/pos_table_views.xml",
+        "views/pos_floor_views.xml",
+        "views/pos_config_views.xml",
+        "views/pos_order_views.xml",
+        "pos_restaurant_table_management.xml",
+    ],
+    "qweb": [
+        "static/src/xml/pos_restaurant_table_management.xml",
+    ],
+}

+ 7 - 0
models/__init__.py

@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import (
+        pos_config, pos_floor, pos_floor_config,
+        pos_order, pos_table)

+ 20 - 0
models/pos_config.py

@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import models, fields
+
+
+class PosConfig(models.Model):
+    _inherit = "pos.config"
+
+    floor_ids = fields.Many2many(
+        "pos.floor",
+        "floor_table_rel",
+        "pos_id",
+        "pos_config_id",
+        "Agrupar por"
+        )
+    iface_floorplan = fields.Boolean(
+        string='Mostrar Mesas/Delivery',
+    )

+ 35 - 0
models/pos_floor.py

@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import models, fields
+
+
+class PosFloor(models.Model):
+    _name = "pos.floor"
+    _description = "Restaurant Floor"
+
+    name = fields.Char(
+        string="Nombre del grupo",
+        required=True,
+        )
+        
+    type = fields.Selection([
+        ('table','Mesa'),
+        ('delivery','Delivery')],
+        string="Tipo",
+        required=True
+    )
+    pos_config_id = fields.Many2many(
+        "pos.config",
+        "floor_table_rel",
+        "pos_config_id",
+        "pos_id",
+        "PoS",
+        required=True,
+        )
+    table_ids = fields.One2many(
+        string="Mesas/Delivery",
+        comodel_name="pos.table",
+        inverse_name="floor_id",
+        )

+ 21 - 0
models/pos_floor_config.py

@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import models, fields
+
+
+class PosFloorConfig(models.Model):
+    _name = "pos.floor_config"
+    _description = "PoS Floor Config"
+
+    pos_id = fields.Many2one(
+        string="TPV",
+        comodel_name="pos.config",
+        required=True,
+        )
+    floor_id = fields.Many2one(
+        string="Agrupado por",
+        comodel_name="pos.floor",
+        required=True,
+        )

+ 23 - 0
models/pos_order.py

@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import models, fields
+
+
+class PosOrder(models.Model):
+    _inherit = "pos.order"
+
+    table_id = fields.Many2one(string="Mesas/Delivery",comodel_name="pos.table")
+    pos_type = fields.Selection([
+        ('table','Mesa'),
+        ('delivery','Delivery')], related='table_id.type',string="Tipo", store=True, readonly=True)
+    employee_id = fields.Many2one(related='table_id.employee_id', string="Choferes", store=True, readonly=True)
+
+    def _order_fields(self, cr, uid, ui_order, context=None):
+        res = super(PosOrder, self)._order_fields(
+            cr, uid, ui_order, context=context
+        )
+        if "table" in ui_order:
+            res['table_id'] = ui_order['table']['id']
+        return res

+ 47 - 0
models/pos_table.py

@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import models, fields, api
+
+
+class PosTable(models.Model):
+    _name = "pos.table"
+    _description = "PoS Table"
+
+    name = fields.Char(string="Nombre")
+    employee_id = fields.Many2one(
+        string="Chofer",
+        comodel_name="hr.employee"
+    )
+    floor_id = fields.Many2one(
+        string="Agrupado por",
+        comodel_name="pos.floor",
+        required=True,
+        )
+    type = fields.Selection([
+        ('table','Mesa'),
+        ('delivery','Delivery')],
+        string="Tipo",
+        required=True,
+        related="floor_id.type"
+    )
+    capacity = fields.Integer(
+        string="Capacidad",
+        )
+    state = fields.Selection(
+        string="Estado",
+        selection=[
+            ("available", "Disponible"),
+            ("vacant", "Vacant"),
+            ("reserved", "Reservado"),
+            ],
+        required=True,
+        default="available",
+        )
+
+    @api.one
+    @api.onchange('employee_id')
+    def onchange_employee_id(self):
+        if self.employee_id:
+            self.name = self.employee_id.name_related

+ 19 - 0
pos_restaurant_table_management.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <template id="indexs" inherit_id='point_of_sale.index' name="POS Header">
+            <xpath expr="//link[@id='pos-stylesheet']" position="after">
+                <link rel="stylesheet" href="/pos_restaurant_table_and_delivery/static/src/css/pos.css" />
+            </xpath>
+        </template>
+
+        <template id="assets_backends_js" name="pos_restaurant_table_and_delivery assests" inherit_id="web.assets_backend">
+            <xpath expr="." position="inside">
+               <script type="text/javascript" src="/pos_restaurant_table_and_delivery/static/src/js/db.js"></script>
+               <script type="text/javascript" src="/pos_restaurant_table_and_delivery/static/src/js/main.js"></script>
+               <script type="text/javascript" src="/pos_restaurant_table_and_delivery/static/src/js/models.js"></script>
+               <script type="text/javascript" src="/pos_restaurant_table_and_delivery/static/src/js/widget.js"></script>
+            </xpath>
+        </template>
+    </data>
+</openerp>

+ 4 - 0
security/ir.model.access.csv

@@ -0,0 +1,4 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_pos_floor_config,pos.floor_config,model_pos_floor_config,,1,1,1,1
+access_pos_floor,pos.floor,model_pos_floor,,1,1,1,1
+access_pos_table,pos.table,model_pos_table,,1,1,1,1

BIN
static/description/icon.png


+ 26 - 0
static/src/css/pos.css

@@ -0,0 +1,26 @@
+.pos .clientlist-screen .button.select-table {
+    left: 50%;
+    margin-left: 190px;
+}
+
+.pos .popup .floor-button2 {
+    height: 100px;
+    display: block;
+    width: 100px;
+    margin: 0px -6px 4px -2px;
+    font-weight: bold;
+    vertical-align: middle;
+    color: #555555;
+    font-size: 14px;
+}
+
+.pos .popup .table-button {
+    height: 100px;
+    display: block;
+    width: 100px;
+    margin: 0px -6px 4px -2px;
+    font-weight: bold;
+    vertical-align: middle;
+    color: #555555;
+    font-size: 14px;
+}

BIN
static/src/img/delivery.png


BIN
static/src/img/driver.png


BIN
static/src/img/rojo.jpg


BIN
static/src/img/table.png


BIN
static/src/img/table2.png


BIN
static/src/img/verde.jpg


+ 56 - 0
static/src/js/db.js

@@ -0,0 +1,56 @@
+function pos_restaurant_table_management_db(instance, module){
+    var QWeb = instance.web.qweb;
+    _t = instance.web._t;
+
+    // DB-1
+    // Module yang mengatur Database di POS
+    module.PosDB = module.PosDB.extend({
+        // Initiasi Awal
+        init: function(options){
+            this.table_by_floor_id = {} // Mendefinisikan variabel
+            this.table_by_id = {} // Mendefinisikan variabel
+            this._super(options);
+        },
+        // DB-1.1
+        // Fungsi Add Table
+        add_tables: function(tables){
+            var stored_tables = this.table_by_floor_id;
+
+            if(!tables instanceof Array){
+                tables = [tables];
+            }
+
+            for(var i=0, len=tables.length; i<len; i++){
+                var table = tables[i];
+                var floor_id = table.floor_id[0];
+                if(!stored_tables[floor_id]){
+                    stored_tables[floor_id] = [];
+                }
+                stored_tables[floor_id].push(table.id);
+                this.table_by_id[table.id] = table;
+            }
+        },
+        // DB-1.2
+        // Fungsi Mencari table berdasarkan ID
+        get_table_by_id: function(id){
+            return this.table_by_id[id];
+        },
+
+        // DB-1.3
+        // Fungsi Mencari table berdasarkan Floor
+        get_table_by_floor: function(floor_id){
+            var table_ids = this.table_by_floor_id[floor_id];
+            var list = [];
+            if (table_ids){
+                for (var i = 0, len=table_ids.length; i<len; i++){
+                    list.push(this.table_by_id[table_ids[i]]);
+                }
+            }
+            return list;
+        },
+
+    });
+
+
+};
+

+ 7 - 0
static/src/js/main.js

@@ -0,0 +1,7 @@
+// Proses mendaftarkan instance di POS
+openerp.pos_restaurant_table_and_delivery = function(instance) {
+    var module = instance.point_of_sale;
+    pos_restaurant_table_management_db(instance, module);
+    pos_restaurant_table_management_models(instance, module);
+    pos_restaurant_table_management_widget(instance, module);
+};

+ 95 - 0
static/src/js/models.js

@@ -0,0 +1,95 @@
+function pos_restaurant_table_management_models(instance, module){
+    var QWeb = instance.web.qweb;
+    _t = instance.web._t;
+
+    // M-1
+    // Menambahkan object baru pos.floor ke model POS
+    module.PosModel.prototype.models.push({
+        model: "pos.floor", // Nama model baru yang dibuat
+        fields: ["name","type"], // Fields yang akan dipanggil
+        domain: function(self){ return [["id", "in", self.config.floor_ids]]}, // Domain
+        loaded: function(self, floors){ // Fungsi ketika di model ini diload oleh JS
+            // Jika FloorPlan == True
+            if(self.config.iface_floorplan){
+                self.floors = floors; // Mendefinisikan variabel floors
+                // Menampung data floors yang diload pada floor_list
+                self.set({
+                    'floor_list' : floors
+                })
+            }// Jika FloorPlan == False
+            else{
+                self.set({'floor_list' :[]});
+            }
+        },
+    });
+
+    // M-2
+    // Menambahkan object baru pos.table ke model POS
+    module.PosModel.prototype.models.push({
+        model: "pos.table",
+        fields: ["name", "capacity", "state", "floor_id","employee_id","type"],
+        domain: function(self){ return [["floor_id", "in", self.config.floor_ids]]},
+        loaded: function(self, tables){
+            // Jika FloorPlan == True
+            if(self.config.iface_floorplan){
+                self.tables = tables;
+                self.db.add_tables(tables);
+            }
+        },
+    });
+
+    // M-3
+    // Menambahkan fungsi set_table pada module Order
+    var _super = module.Order;
+    module.Order = module.Order.extend({
+        // M-3.1
+        // Membuat Fungsi untuk menampung data ID Table
+        set_table: function(table){
+            this.set('table',table);
+        },
+        // M-3.2
+        // Membuat Fungsi untuk mengambil data ID Table
+        get_table: function(){
+            return this.get('table');
+        },
+        // M-3.3
+        // Membuat Fungsi untuk mengambil nama Table
+        // Fungsi ini dipakai pada /src/xml/pos_table_management.xml
+        // Lihat T-7
+        get_table_name: function(){
+            var table = this.get('table');
+            return table ? table.name : "";
+        },
+
+        // M-3.4
+        // Inherit Fungsi export_as_JSON
+        // Fungsi ini digunakan untuk mengeksport data yang akan dimasukan ke object pos.order
+        export_as_JSON: function(){
+            var json = _super.prototype.export_as_JSON.apply(this,arguments);
+            // Menambahkan variabel tabel
+            json.table = this.get_table();
+
+            return json;
+        },
+    });
+
+    // Tables
+
+    // module.TableListWidget = module.TableListWidget.include({
+    //
+    //     set_state: function(state){
+    //         this.set('state',state);
+    //     },
+    //
+    //     get_state: function(){
+    //         return this.get('state');
+    //     },
+    //
+    //     export_as_JSON: function(){
+    //         var json = _super.prototype.export_as_JSON.apply(this,arguments);
+    //         // Menambahkan variabel tabel
+    //         json.state = this.get_state();
+    //         return json;
+    //     },
+    // })
+};

+ 347 - 0
static/src/js/widget.js

@@ -0,0 +1,347 @@
+function pos_restaurant_table_management_widget(instance, module){
+    var QWeb = instance.web.qweb;
+    var model = openerp;
+    _t = instance.web._t;
+
+    // S-1
+    // Module yang mengatur Widget di POS
+    module.PosWidget.include({
+        // S-1.1
+        // Nama Fungsi untuk mendaftakan widget baru yang dibuat
+        build_widgets: function() {
+
+            var self = this;
+            this._super();
+
+            //S.1-2
+            // Proses mendaftarkan widget yang baru untuk Floor
+            this.floor_popup = new module.FloorPopUp(this,{}); // Mendefinisikan module widget baru ke dalam variabel (this.floor_popup). Lihat S-3
+            this.floor_popup.appendTo(this.$el); // Memasukan widget baru ke dalam screen
+            this.floor_popup.hide(); // Widget baru kemudian dibuat invisible
+            this.screen_selector.popup_set['floors'] = this.floor_popup;  // Mendefinisikan pop up untuk nanti dipanggil ke dalam variabel (floors)
+
+            //S.1-3
+            // Proses mendaftarkan widget yang baru untuk Table
+            this.table_popup = new module.TablePopUp(this,{}); // Mendefinisikan module widget baru ke dalam variabel (this.table_popup). Lihat S-6
+            this.table_popup.appendTo(this.$el);// Memasukan widget baru ke dalam screen
+            this.table_popup.hide(); // Widget baru kemudian dibuat invisible
+            this.screen_selector.popup_set['tables'] = this.table_popup; // Mendefinisikan pop up untuk nanti dipanggil ke dalam variabel (tables)
+        }
+    });
+
+    // S-2
+    // Module yang mengatur Client Screen di POS
+    module.ClientListScreenWidget.include({
+        // S-2.1 Proses menambahkan tombol baru pada Client Screen
+        // Tombol baru sudah ditambahkan pada xml Client Screen /src/xml/pos_table_management.xml
+        // Lihat T-1
+        show: function(){
+            var self = this;
+            this._super();
+            var floor_list = self.pos.get('floor_list');
+
+            if(floor_list){
+                // Membuat fungsi pada saat tombol "Select Table" di-klik
+                this.$('.select-table').click(function(){
+                    // Menampilkan widget Pop Up yang sudah didefinisikan di awal pada S.1-2
+                    self.pos_widget.screen_selector.show_popup('floors');
+                    // Membuat fungsi pada saat tombol "Cancel" di-klik
+                    // Tombol ini berada pada template Pop Up Floor yang sudah dimunculkan
+                    $('#floor-cancel').click(function(){
+                        // Menampilkan widget Pop Up Client Screen
+                        // Pop up ini sudah didaftarkan pada module default point_of_sale
+                        self.pos_widget.screen_selector.set_current_screen('clientlist');
+                    });
+                });
+            }
+            else{
+                this.$el.removeClass('.select-table');
+            }
+        }
+    });
+
+    // S-3
+    // Module yang mengatur widget PopUp
+    // Module ini didaftarkan pada S.1-2
+    module.FloorPopUp = module.PopUpWidget.extend({
+        // Mendefinisikan template Pop Up yang dibuat
+        // Template dibuat pada xml Client Screen /src/xml/pos_table_management.xml
+        // Lihat T-2
+        template:'FloorPopupWidget',
+
+        // Fungsi Start ini akan dijalankan pertama kali setelah initiasi awal ketika module ini dipanggil
+        start: function(){
+            this._super();
+            var self = this;
+            // S-3.1
+            // Mendefinisikan Screen Widget Untuk Floor yang dibuat pada S-4
+            this.floor_list_widget = new module.FloorListScreenWidget(this,{});
+        },
+
+        // Fungsi Show ini akan dijalankan ketika Pop Up muncul ke screen
+        show: function(){
+            this._super();
+            var self = this;
+            // Proses mengganti DOM pada template dengan Screen Widget yang sudah didefiniskan pada S.3.-1
+            // Struktur DOM bisa dilihat pada /src/xml/pos_table_management.xml
+            // Lihat T-2
+            this.floor_list_widget.replace($('.placeholder-FloorListScreenWidget'));
+        },
+    });
+
+    // S-4
+    // Module yang mengatur widget Screen
+    module.FloorListScreenWidget = module.ScreenWidget.extend({
+        // Mendefinisikan template Screen yang dibuat
+        // Template dibuat pada xml Client Screen /src/xml/pos_table_management.xml
+        // Lihat T-3
+        template:'FloorListScreenWidget',
+
+        // Fungsi yang mengatur initiasi awal
+        init: function(parent, options) {
+            this._super(parent,options);
+        },
+
+        // Fungsi Start ini akan dijalankan pertama kali setelah initiasi awal ketika module ini dipanggil
+        start: function() {
+            this._super();
+            var self = this;
+        },
+
+        // Fungsi RenderElement mengatur element DOM pada template
+        renderElement: function() {
+            this._super();
+            var self = this;
+
+            // Mendefiniskan List Floor yang ada ke dalam Variabel
+            // floor_list sudah didaftarkan pada /src/js/models.js
+            // Lihat M-1
+            var floors = this.pos.get('floor_list') || [];
+            // Proses Memasukan data pada template
+            // Melakukan looping terhadap data floor yang ada
+            for(var i = 0; i < floors.length;  i++ ){
+                // Mendefinisikan Widget Floor List
+                // Melakukan parsing parameter model_floor
+                // Nantinya variable ini akan dipakai sebagai element untuk menampilkan data di Template
+                var floor = new module.FloorListWidget(this, {
+                    model_floor: floors[i],
+                });
+                // Template yang sudah didefiniskan di atas di append ke DOM '.floor_list'
+                // '.floor_list' ada pada T-3
+                floor.appendTo(this.$('.floor_list'));
+            }
+        },
+    }),
+
+    // S-5
+    // Module yang mengatur Widget di POS
+    // Proses membuat widget baru untuk menampilkan list floor
+    module.FloorListWidget = module.PosBaseWidget.extend({
+        // Mendefinisikan Template
+        // Template dibuat pada xml Client Screen /src/xml/pos_table_management.xml
+        // Lihat T-4
+        template: 'FloorListWidget',
+
+        // Fungsi yang mengatur initiasi awal
+        init: function(parent, options){
+            this._super(parent, options);
+            this.model_floor = options.model_floor;
+        },
+
+        // Fungsi RenderElement mengatur element DOM pada template
+        renderElement: function(){
+            var self = this;
+            this._super();
+
+            // Membuat fungsi untuk setiap tombol floor apabila di-klik
+            $("button", this.$el).click(function(e){
+              var type = $(this).attr('data-floor-type');
+              var title;
+
+              if (type == 'table'){
+                title = "Mesas"
+              }else {
+                title = "Delivery"
+              }
+                // S-5.1
+                // Memasukan data tabel berdasarkan floor
+                // Data dimasukan ke dalam Fungsi "set_table_list"
+                // Fungsi tersebut ada pada Module TablePopUp yang sudah didefinisikan di awal pada S.1-3
+                // Lihat S-6.1
+                // Fungsi get_table_by_floor ada pada /src/js/db.js
+                // Lihat DB-1.3
+                self.pos_widget.table_popup.set_table_list(self.pos.db.get_table_by_floor(self.model_floor.id),title);
+                // Menampilkan widget Pop Up yang sudah didefinisikan di awal pada S.1-3
+                self.pos_widget.screen_selector.show_popup("tables");
+            });
+        }
+    });
+
+    // S-6
+    // Module yang mengatur widget PopUp
+    // Module ini didaftarkan pada S.1-3
+    module.TablePopUp = module.PopUpWidget.extend({
+        // Mendefinisikan template Pop Up yang dibuat
+        // Template dibuat pada xml Client Screen /src/xml/pos_table_management.xml
+        // Lihat T-5
+        template: "TablePopupWidget",
+
+        // Fungsi initiasi awal
+        init: function(parent, options){
+            var self = this;
+            this._super(parent, options);
+            this.table_list = options.table_list || []; // Membuat variabel baru
+
+        },
+
+        // S-6.1
+        // Fungsi untuk menampung data table dari S-5.1
+        set_table_list: function(table_list, title){
+            var self = this;
+            this.table_list = table_list;
+            self.fetchInicial(title);
+        },
+
+       fetchInicial: function(title){
+         var self = this;
+         this.fetchHrEmployee().then(function(HrEmployee) {
+            return HrEmployee;
+          }).then(function (HrEmployee){
+            self.HrEmployee = HrEmployee;
+            return self.renderElement(title);
+          });
+       },
+
+       fetchHrEmployee: function() {
+          var self = this;
+          var defer = $.Deferred();
+          var fields = ['id','name','image_small'];
+          var domain = [['active','=', true]];
+          var HrEmployee = new model.web.Model('hr.employee');
+          HrEmployee.query(fields).filter(domain).all().then(function (results) {
+              defer.resolve(results);
+          });
+          return defer;
+      },
+
+      getUserImage: function (id) {
+           var self = this;
+           return _.map(_.filter(self.HrEmployee,function (item) {
+               return item.id == id;
+           }), function(map){
+             return map.image_small
+           });
+       },
+
+       get_availability: function (id) {
+            var self = this;
+            var available = true;
+            _.each(_.map(_.filter(self.pos.get('orders').models,function (item) {
+                return item.attributes.table;
+            }), function(map){
+              return map.attributes.table.id;
+
+            }), function(each){
+              if(each == id){
+                available = false;
+              }
+            });
+            return available
+        },
+
+        // S-6.2
+        // Fungsi RenderElement mengatur element DOM pada template
+        renderElement: function(title) {
+            var self = this;
+            this._super();
+
+            this.$(".floor-heading").append('<a>'+title+'</a>');
+            // Mendefiniskan List Table yang ada ke dalam Variabel
+            // this.table_list sudah diset pada S-6.1
+            var tables = this.table_list || [];
+
+
+            // Proses Memasukan data pada template
+            // Melakukan looping terhadap data table yang ada
+            for(var i = 0; i < tables.length;  i++ ){
+              var image_small;
+              var available = true;
+
+              if(tables[i].type == 'delivery'){
+                var image = self.getUserImage(tables[i].employee_id[0]);
+                if(image[0] == false || image[0] == undefined){
+                    image_small = "/pos_restaurant_table_and_delivery/static/src/img/driver.png"
+                }else {
+                    image_small = "data:image/*;base64,"+image[0];
+                }
+              }else {
+                available = self.get_availability(tables[i].id);
+
+                  if(available || available == undefined){
+                      image_small = "/pos_restaurant_table_and_delivery/static/src/img/verde.jpg"
+                  }
+                  else {
+                      image_small = "/pos_restaurant_table_and_delivery/static/src/img/rojo.jpg"
+                  }
+              }
+                tables[i]['image'] = image_small;
+
+                // Mendefinisikan Widget Table List
+                // Melakukan parsing parameter model_table
+                // Nantinya variable ini akan dipakai sebagai element untuk menampilkan data di Template
+                var table = new module.TableListWidget(this, {
+                    model_table: tables[i],
+                });
+
+                // Template yang sudah didefiniskan di atas di append ke DOM '.table_data'
+                // '.table_data' ada pada T-5
+
+                 // this.$(".imagen_small").append('<img src="data:image/png;base64,'+image+'/>');
+                table.appendTo(this.$('.table-data'));
+            }
+
+            $('#table-back').click(function(){
+                // Menampilkan widget Pop Up Floors
+                // Pop up ini sudah didaftarkan pada S-1.2
+                self.pos_widget.screen_selector.show_popup("floors");
+            });
+        },
+    });
+
+    // S-7
+    // Module yang mengatur Widget di POS
+    // Proses membuat widget baru untuk menampilkan list table
+    module.TableListWidget = module.PosBaseWidget.extend({
+        // Mendefinisikan Template
+        // Template dibuat pada xml Client Screen /src/xml/pos_table_management.xml
+        // Lihat T-6
+        template: 'TableListWidget',
+
+        // Fungsi yang mengatur initiasi awal
+        init: function(parent, options){
+            this._super(parent, options);
+            this.model_table = options.model_table;
+        },
+
+        // Fungsi RenderElement mengatur element DOM pada template
+        renderElement: function(){
+            this._super();
+            var self = this;
+
+            // Membuat fungsi pada saat data tabel di-klik
+            $("button", this.$el).click(function(e){
+                // S-7.1
+                // Memasukan data tabel
+                // Data dimasukan ke dalam Fungsi "set_table"
+                // Fungsi tersebut ada pada Module Order pada /src/js/model.js
+                // Lihat M-3.1
+
+                self.pos.get('selectedOrder').set_table(self.model_table);
+                // self.pos.get('selectedOrder').set_state('reserved');
+                // Fungsi ini untuk mengembalikan screen ke awal
+                self.pos_widget.screen_selector.back();
+            });
+        },
+    });
+
+};

+ 168 - 0
static/src/xml/pos_restaurant_table_management.xml

@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates id="template" xml:space="preserve">
+
+
+    <!--
+        T-1
+        Inherit Template Client Screen
+        Menambahkan Tombol "Select Table"
+    -->
+    <t t-extend="ClientListScreenWidget">
+        <t t-jquery="span.new-customer" t-operation="after">
+            <span class="button select-table">
+                Elegir
+            </span>
+        </t>
+    </t>
+
+    <!--
+        T-2
+        Membuat Template Pop Up Widget Untuk Floor
+    -->
+    <t t-name="FloorPopupWidget">
+        <div class="modal-dialog custom-dialog">
+            <div class="popup popup-select-floors" >
+                <div class="floor-header">
+                    <!-- <div class="floor-heading">
+                        Elegir salon o piso
+                    </div> -->
+                    <div class=" button" id="floor-cancel">
+                        Cancelar
+                    </div>
+                </div>
+                <div class="floor-data" style="margin-top:70px">
+                    <span class="placeholder-FloorListScreenWidget" />
+                </div>
+            </div>
+        </div>
+    </t>
+
+    <!--
+        T-3
+        Membuat Template Screen Widget Untuk Floor
+    -->
+    <t t-name="FloorListScreenWidget">
+        <div class="floor_list_class">
+            <ol  class="floor_list">
+            </ol>
+        </div>
+    </t>
+
+    <!--
+        T-4
+        Membuat Template List Widget Untuk Floor
+    -->
+    <t t-name="FloorListWidget">
+      <style>
+        .floor-button2 {
+            height: 100px;
+            width: 100px;
+            font-weight: bold;
+            vertical-align: middle;
+            color: #555555;
+            font-size: 14px !important;
+            display: inline !important;
+            margin: 0 !important;
+        }
+      </style>
+        <span class='floor_list_widget' t-att-data-floor-id="widget.model_floor.id">
+            <button class="floor-button2" t-att-data-floor-type="widget.model_floor.type">
+                <t t-if="widget.model_floor.type == 'table'">
+                  <img src="/pos_restaurant_table_and_delivery/static/src/img/table2.png" style="width:50px"/>
+                </t>
+                <t t-if="widget.model_floor.type == 'delivery'">
+                  <img src="/pos_restaurant_table_and_delivery/static/src/img/delivery.png" style="width:50px"/>
+                </t>
+                <t t-esc="widget.model_floor.name"/>
+            </button>
+        </span>
+    </t>
+
+    <!--
+        T-5
+        Membuat Template Pop Up Widget Untuk Table
+    -->
+
+    <t t-name="TablePopupWidget">
+        <div class="modal-dialog custom-dialog">
+            <div class="popup popup-select-table" >
+                <div class="floor-heading">
+                </div>
+                <span class='button' id='table-back'>
+                    <i class='fa fa-angle-double-left'></i>
+                    Volver
+                </span>
+                <span class='button next oe_hidden highlight'>
+                    Set Customer
+                    <i class='fa fa-angle-double-right'></i>
+                </span>
+                <div class="table-data" style="margin-top:70px">
+                </div>
+            </div>
+        </div>
+
+    </t>
+
+    <!--
+        T-6
+        Membuat Template List Widget Untuk Table
+    -->
+    <t t-name="TableListWidget">
+      <style>
+        .table-button2 {
+            height: 110px;
+            width: 110px;
+            font-weight: bold;
+            vertical-align: middle;
+            color: #555555;
+            font-size: 14px !important;
+        }
+        .img-table{
+          width: 100% !important;
+
+        }
+        .img-driver{
+          width:70px !important;
+        }
+        .table-text{
+          position: absolute;
+          top:50%;
+          left:50%;
+          transform: translate(-50%, -50%);
+          color: black;
+        }
+      </style>
+        <span class='table_list_widget' t-att-data-floor-id="widget.model_table.id">
+            <button class="table-button2" style="position:relative">
+              <t t-if="widget.model_table.type == 'table'">
+                  <img t-attf-src="{{widget.model_table.image}}" class="img-table"/>
+                  <div class="table-text">
+                    <t t-esc="widget.model_table.name"/>
+                  </div>
+              </t>
+              <t t-if="widget.model_table.type == 'delivery'">
+                  <img t-attf-src="{{widget.model_table.image}}" class="img-driver"/>
+                  <div>
+                    <t t-esc="widget.model_table.name"/>
+                  </div>
+              </t>
+            </button>
+        </span>
+    </t>
+
+    <!--
+        T-7
+        Menambahkan Informasi Table pada tab order
+    -->
+    <t t-extend="OrderButtonWidget">
+        <t t-jquery="span.order-sequence" t-operation="after">
+            <span class='order-table'>
+                <t t-if="widget.order.get_table()">
+                    <i class='fa'/>
+                    <img src="/pos_restaurant_table_and_delivery/static/src/img/table.png"/>
+                    <t t-esc="widget.order.get_table_name()"/>
+                </t>
+            </span>
+        </t>
+    </t>
+</templates>

+ 28 - 0
views/pos_config_views.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 OpenSynergy Indonesia
+     License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
+
+<openerp>
+    <data>
+
+        <record id="pos_config_view_form" model="ir.ui.view">
+            <field name="name">PoS Config Form</field>
+            <field name="model">pos.config</field>
+            <field name="inherit_id" ref="pos_restaurant.view_pos_config_form"/>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='iface_printbill']" position="after">
+                    <field name="iface_floorplan"/>
+                </xpath>
+                <xpath expr="//field[@name='printer_ids']" position="after">
+                    <separator string="Agrupar por" colspan="4"/>
+                    <field name="floor_ids" colspan="4" nolabel="1">
+                        <tree editable="top">
+                            <field name="name"/>
+                        </tree>
+                    </field>
+                </xpath>
+            </field>
+        </record>
+
+    </data>
+</openerp>

+ 64 - 0
views/pos_floor_views.xml

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 OpenSynergy Indonesia
+     License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
+
+<openerp>
+<data>
+
+<record id="pos_floor_view_tree" model="ir.ui.view">
+    <field name="name">Tree PoS Floor</field>
+    <field name="model">pos.floor</field>
+    <field name="arch" type="xml">
+        <tree>
+            <field name="name"/>
+            <field name="type"/>
+            <field name="pos_config_id" string="TPV"/>
+        </tree>
+    </field>
+</record>
+
+<record id="pos_floor_view_form" model="ir.ui.view">
+    <field name="name">Form PoS Floor</field>
+    <field name="model">pos.floor</field>
+    <field name="arch" type="xml">
+        <form string="Floors">
+            <sheet>
+                <group col="4">
+                    <field name="type" widget="radio"/>
+                    <field name="name" string="Nombre del grupo"/>
+                    <field name="pos_config_id" string="Terminal de Venta" widget="many2many_tags"
+                    options="{'no_create_edit': True,'no_quick_create': True}"/>
+                </group>
+                <field name="table_ids" string="Mesas/Delivery">
+                    <tree string="Mesas/Delivery" create="false">
+                        <field name="name"/>
+                    </tree>
+                </field>
+            </sheet>
+        </form>
+    </field>
+</record>
+
+<record id="pos_floor_action" model="ir.actions.act_window">
+    <field name="name">Agrupar por</field>
+    <field name="type">ir.actions.act_window</field>
+    <field name="res_model">pos.floor</field>
+    <field name="view_type">form</field>
+    <field name="view_mode">tree,form</field>
+    <field name="help" type="html">
+        <p class="oe_view_nocontent_create">
+            Pulse para registrar un nuevo piso o delivery.
+        </p>
+    </field>
+</record>
+
+<menuitem
+    id="pos_floor_menu"
+    name="Grupos"
+    parent="point_of_sale.menu_point_config_product"
+    groups="point_of_sale.group_pos_manager"
+    action="pos_floor_action"
+/>
+
+</data>
+</openerp>

+ 51 - 0
views/pos_order_views.xml

@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright <YEAR(S)> <AUTHOR(S)>
+     License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
+
+<openerp>
+    <data>
+
+        <record id="pos_order_view_form" model="ir.ui.view">
+            <field name="name">Inherit : Order Tables Form</field>
+            <field name="model">pos.order</field>
+            <field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='partner_id']" position="after">
+                    <field name="table_id" string="Mesa/Delivery"/>
+                </xpath>
+            </field>
+        </record>
+
+        <record id="pos_order_view_tree" model="ir.ui.view">
+            <field name="name">Inherit : Order Tables Tree</field>
+            <field name="model">pos.order</field>
+            <field name="inherit_id" ref="point_of_sale.view_pos_order_tree"/>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='partner_id']" position="after">
+                    <field name="table_id" string="Mesa/Delivery"/>
+                    <field name="pos_type" invisible="1"/>
+                    <field name="employee_id" invisible="1"/>
+                </xpath>
+            </field>
+        </record>
+
+        <record id="pos_delivery_search_view" model="ir.ui.view">
+            <field name="name">pos_delivery_search_view</field>
+            <field name="model">pos.order</field>
+            <field name="inherit_id" ref="point_of_sale.view_pos_order_filter"/>
+            <field name="arch" type="xml">
+              <search>
+
+                  <filter string="Mesas" domain="[('table_id.type','=','table')]"/>
+                  <filter string="Delivery" domain="[('table_id.type','=','delivery')]"/>
+
+                   <group string="">
+                        <filter string="Tipo" context="{'group_by':'pos_type'}"/>
+                        <filter string="Choferes" context="{'group_by':'employee_id'}"/>
+                    </group>
+                </search>
+            </field>
+        </record>
+
+    </data>
+</openerp>

+ 57 - 0
views/pos_table_views.xml

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 OpenSynergy Indonesia
+     License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
+
+<openerp>
+<data>
+
+<record id="pos_table_view_tree" model="ir.ui.view">
+    <field name="name">Tree Pos Table</field>
+    <field name="model">pos.table</field>
+    <field name="arch" type="xml">
+        <tree>
+            <field name="name" string="Nombre"/>
+            <field name="type" string="Tipo"/>
+            <field name="floor_id" string="Grupo"/>
+            <field name="capacity" string="Número de asientos" attrs="{'invisible': [('type', '!=', 'table')]}"/>
+        </tree>
+    </field>
+</record>
+
+<record id="pos_table_view_form" model="ir.ui.view">
+    <field name="name">Form Pos Table</field>
+    <field name="model">pos.table</field>
+    <field name="arch" type="xml">
+        <form string="Restaurant Table">
+            <!-- <header>
+                <field name="state" widget="statusbar"/>
+            </header> -->
+            <group name="grp_pos_table">
+                <field name="floor_id" string="Agrupar por"/>
+                <field name="type" string="Tipo" widget="radio" readonly="1"/>
+                <field name="name" string="Nro de Mesa" attrs="{'invisible': [('type', '!=', 'table')], 'required':[('type','=','table')]}"/>
+                <field name="employee_id" string="Chofer" attrs="{'invisible': [('type', '!=', 'delivery')], 'required':[('type','=','delivery')]}"/>
+                <field name="capacity" string="Número de asientos" attrs="{'invisible': [('type', '!=', 'table')]}"/>
+            </group>
+        </form>
+    </field>
+</record>
+
+<record id="pos_table_action" model="ir.actions.act_window">
+    <field name="name">Mesas o Delivery</field>
+    <field name="type">ir.actions.act_window</field>
+    <field name="res_model">pos.table</field>
+    <field name="view_type">form</field>
+    <field name="view_mode">tree,form</field>
+</record>
+
+<menuitem
+    id="pos_table_menu"
+    name="Mesas o Delivery"
+    parent="point_of_sale.menu_point_config_product"
+    groups="point_of_sale.group_pos_manager"
+    action="pos_table_action"
+    />
+
+</data>
+</openerp>