Browse Source

pos_combinated_drinks

pull/432/head
manuelcalerosolis 5 years ago
parent
commit
63cebcc2c7
  1. 1
      pos_combinated_drinks/README.md
  2. 7
      pos_combinated_drinks/__init__.py
  3. 23
      pos_combinated_drinks/__manifest__.py
  4. 154
      pos_combinated_drinks/i18n/es.po
  5. 5
      pos_combinated_drinks/models/__init__.py
  6. 9
      pos_combinated_drinks/models/point_of_sale.py
  7. 21
      pos_combinated_drinks/models/product.py
  8. 2
      pos_combinated_drinks/security/ir.model.access.csv
  9. BIN
      pos_combinated_drinks/static/description/icon.png
  10. 130
      pos_combinated_drinks/static/src/css/pos.css
  11. 161
      pos_combinated_drinks/static/src/js/pos.js
  12. 51
      pos_combinated_drinks/static/src/xml/pos.xml
  13. 34
      pos_combinated_drinks/views/point_of_sale.xml
  14. 14
      pos_combinated_drinks/views/pos_combined_drinks.xml

1
pos_combinated_drinks/README.md

@ -0,0 +1 @@
# pos_combinated_drinks

7
pos_combinated_drinks/__init__.py

@ -0,0 +1,7 @@
# Copyright 2019 Xtendoo (http://www.xtendoo.es)
# Copyright 2019 Manuel Calero Solís
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from .import models

23
pos_combinated_drinks/__manifest__.py

@ -0,0 +1,23 @@
# Copyright 2019 Xtendoo (http://www.xtendoo.es)
# Copyright 2019 Manuel Calero Solís
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Pos Combinated Drinks',
'version': '13.0.1.0.0',
'category': 'Point of Sale',
'author': 'Xtendoo',
'website': 'https://www.xtendoo.es',
'license': 'AGPL-3',
'summary': 'This module allows to use combined drinks in a bar or restaurant',
'version': '1.0.1',
'depends': ['base', 'pos_restaurant'],
"data": [
'security/ir.model.access.csv',
'views/point_of_sale.xml',
'views/pos_combined_drinks.xml',
],
'qweb': ['static/src/xml/pos.xml'],
'installable': True,
'auto_install': False,
}

154
pos_combinated_drinks/i18n/es.po

@ -0,0 +1,154 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * pos_combinated_drinks
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0-20191025\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-12-12 22:26+0000\n"
"PO-Revision-Date: 2019-12-12 22:26+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: pos_combinated_drinks
#. openerp-web
#: code:addons/pos_combinated_drinks/static/src/xml/pos.xml:0
#, python-format
msgid "% discount"
msgstr ""
#. module: pos_combinated_drinks
#. openerp-web
#: code:addons/pos_combinated_drinks/static/src/xml/pos.xml:0
#, python-format
msgid "Cancel"
msgstr ""
#. module: pos_combinated_drinks
#: model_terms:ir.ui.view,arch_db:pos_combinated_drinks.package_product_template_only_form_view
msgid "Categories"
msgstr ""
#. module: pos_combinated_drinks
#. openerp-web
#: code:addons/pos_combinated_drinks/static/src/xml/pos.xml:0
#, python-format
msgid "Combined product"
msgstr ""
#. module: pos_combinated_drinks
#: model_terms:ir.ui.view,arch_db:pos_combinated_drinks.package_product_template_only_form_view
msgid "Combo"
msgstr ""
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_product__combo_price
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_template__combo_price
msgid "Combo price"
msgstr ""
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_combo__create_uid
msgid "Created by"
msgstr "Creado por"
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_combo__create_date
msgid "Created on"
msgstr "Creado el"
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_combo__display_name
msgid "Display Name"
msgstr "Nombre mostrado"
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_combo__id
msgid "ID"
msgstr ""
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_pos_order_line__invisible
msgid "Invisible Line"
msgstr ""
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_product__is_combo
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_template__is_combo
msgid "Is Combo"
msgstr "Combinable"
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_combo____last_update
msgid "Last Modified on"
msgstr "Última modificación en"
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_combo__write_uid
msgid "Last Updated by"
msgstr "Última actualización por"
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_combo__write_date
msgid "Last Updated on"
msgstr "Última actualización el"
#. module: pos_combinated_drinks
#. openerp-web
#: code:addons/pos_combinated_drinks/static/src/xml/pos.xml:0
#: code:addons/pos_combinated_drinks/static/src/xml/pos.xml:0
#, python-format
msgid "NOTE"
msgstr ""
#. module: pos_combinated_drinks
#: model:ir.model,name:pos_combinated_drinks.model_pos_order_line
msgid "Point of Sale Order Lines"
msgstr "Líneas de Orden de Punto de Venta"
#. module: pos_combinated_drinks
#: model:ir.model,name:pos_combinated_drinks.model_pos_order
msgid "Point of Sale Orders"
msgstr "Pedidos del TPV"
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_product__combo_category_ids
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_template__combo_category_ids
msgid "Pos Categories"
msgstr ""
#. module: pos_combinated_drinks
#: model:ir.model,name:pos_combinated_drinks.model_product_combo
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_product__product_combo_ids
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_template__product_combo_ids
msgid "Product Combo"
msgstr ""
#. module: pos_combinated_drinks
#: model:ir.model,name:pos_combinated_drinks.model_product_template
msgid "Product Template"
msgstr "Plantilla de producto"
#. module: pos_combinated_drinks
#: model:ir.model.fields,field_description:pos_combinated_drinks.field_product_combo__product_tmpl_id
msgid "Product Tmpl"
msgstr ""
#. module: pos_combinated_drinks
#. openerp-web
#: code:addons/pos_combinated_drinks/static/src/xml/pos.xml:0
#, python-format
msgid "Quantity"
msgstr ""
#. module: pos_combinated_drinks
#. openerp-web
#: code:addons/pos_combinated_drinks/static/src/xml/pos.xml:0
#, python-format
msgid "With a"
msgstr ""

5
pos_combinated_drinks/models/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from .import point_of_sale
from .import product

9
pos_combinated_drinks/models/point_of_sale.py

@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
class PosOrderLine(models.Model):
_inherit = "pos.order.line"
invisible = fields.Boolean('Invisible Line', default=False)

21
pos_combinated_drinks/models/product.py

@ -0,0 +1,21 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _
class ProductTemplate(models.Model):
_inherit = "product.template"
is_combo = fields.Boolean("Is Combo")
combo_price = fields.Float('Combo price', company_dependent=True, digits='Product Price', groups="base.group_user")
combo_category_ids = fields.Many2many('pos.category', string='Pos Categories')
product_combo_ids = fields.One2many('product.combo', 'product_tmpl_id')
class ProductCombo(models.Model):
_name = 'product.combo'
_description = 'Product Combo'
product_tmpl_id = fields.Many2one('product.template')

2
pos_combinated_drinks/security/ir.model.access.csv

@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_product_combo,access_product_combo,model_product_combo,point_of_sale.group_pos_user,1,1,1,1

BIN
pos_combinated_drinks/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 9.2 KiB

130
pos_combinated_drinks/static/src/css/pos.css

@ -0,0 +1,130 @@
.product_pack{
background: green;
position: absolute;
top: 69px;
vertical-align: top;
color: white;
line-height: 13px;
padding: 2px 5px;
border-radius: 2px;
opacity: 0.6;
width: 100%;
}
.pos_combo_product_popup .title{
margin-bottom: 8px !important;
}
.pos_combo_product_popup .combo_product_header, .combo_product_header2{
text-align: left;
padding-left: 8px;
font-size: 16px;
height: 30px;
line-height: 30px;
background: #c4c4c4;
border-top: 3px solid #f0eeee;
}
.pos_combo_product_popup .combo_header_body{
text-align: left;
overflow-y: hidden !important;
white-space: nowrap;
height: 112px;
overflow-x: auto !important;
margin-left: 15px;
}
.pos_combo_product_popup .combo_header2_body{
text-align: left;
margin-left: 10px;
margin-right: 7px;
height: 454px;
overflow: auto;
}
.product.product_content{
width: 100px !important;
height: 80px !important;
}
.product.product_content .product-img{
width: 102px !important;
height: 80px !important;
}
.product.product_content.selected {
border: 2px solid cadetblue;
}
.product.product_content.selected .selected_product{
background: green;
position: absolute;
top: 40px;
vertical-align: top;
color: white;
line-height: 13px;
padding: 2px 5px;
border-radius: 2px;
opacity: 0.6;
width: 100%;
}
.pos_combo_product_popup{
height: 600px !important;
width: 630px !important;
}
.collaps_div{
float: right;
margin-right: 7px;
background: #555;
height: 20px;
margin-top: 5px;
color: #fff;
display: flex;
width: 20px;
justify-content: center;
border-radius: 50%;
font-weight: bold;
font-size: larger;
cursor:pointer;
}
.product.product_content .product-qty{
position: absolute;
top: 0px;
left: 0px;
vertical-align: top;
color: white;
line-height: 13px;
background: #7f82ac;
padding: 2px 5px;
}
.product.product_content .product-remove{
position: absolute;
top: 0px;
right: 0px;
vertical-align: top;
line-height: 13px;
padding: 0px 5px;
font-size: 24px;
background: #c4c4c4;
}
.categ_tile{
border: 1px solid #c4c4c4;
width: 99%;
margin-top: 5px;
}
.categ_tile div.categ_name{
font-size: 14px;
padding: 4px 0px;
background: #c4c4c4;
height: 18px;
}
.categ_tile div.categ_name div{
float: left;
width: 50%;
}
.blinking{
animation:blinkingText 2s infinite;
}
@keyframes blinkingText{
50% {
opacity: 0;
}
}
.products_list{
overflow-y: hidden !important;
white-space: nowrap;
overflow-x: auto !important;
margin-left: 5px;
}

161
pos_combinated_drinks/static/src/js/pos.js

@ -0,0 +1,161 @@
odoo.define('pos_combinated_drinks.pos', function (require) {
"use strict";
var PopupWidget = require('point_of_sale.popups');
var models = require('point_of_sale.models');
var gui = require('point_of_sale.gui');
var screens = require('point_of_sale.screens');
models.load_fields("product.product", ['is_combo', 'combo_price', 'product_combo_ids', 'combo_category_ids']);
var _super_Order = models.Order.prototype;
models.Order = models.Order.extend({
add_product: function(product, options){
var self = this;
if(product.is_combo && product.combo_category_ids.length > 0){
// if (product['combo_price'] != 0){
// options = {'price': product['combo_price']}
// }
_super_Order.add_product.call(self, product, options);
self.pos.gui.show_popup('combo_product_popup',{
'product': product
});
}
else{
_super_Order.add_product.call(self, product, options);
}
},
});
var _super_orderline = models.Orderline.prototype;
models.Orderline = models.Orderline.extend({
initialize: function(attr,options){
this.combo_prod_info = false;
_super_orderline.initialize.call(this, attr, options);
},
init_from_JSON: function(json) {
var self = this;
_super_orderline.init_from_JSON.apply(this,arguments);
var new_combo_data = [];
if(json.combo_ext_line_info && json.combo_ext_line_info.length > 0){
json.combo_ext_line_info.map(function(combo_data){
if(combo_data[2].product_id){
var product = self.pos.db.get_product_by_id(combo_data[2].product_id);
if(product){
new_combo_data.push({
'product':product,
'price':combo_data[2].price,
'qty':combo_data[2].qty,
'id':combo_data[2].id,
});
}
}
});
}
self.set_combo_prod_info(new_combo_data);
},
set_combo_prod_info: function(combo_prod_info){
this.combo_prod_info = combo_prod_info;
this.trigger('change',this);
},
get_combo_prod_info: function(){
return this.combo_prod_info;
},
export_as_JSON: function(){
var self = this;
var json = _super_orderline.export_as_JSON.call(this,arguments);
var combo_ext_line_info = [];
if(this.product.is_combo && this.combo_prod_info.length > 0){
_.each(this.combo_prod_info, function(item){
combo_ext_line_info.push([0, 0, {
'product_id':item.product.id,
'qty':item.qty,
'price':item.price,
'id':item.id,
}]);
});
}
json.combo_ext_line_info = this.product.is_combo ? combo_ext_line_info : [];
return json;
},
can_be_merged_with: function(orderline){
var result = _super_orderline.can_be_merged_with.call(this,orderline);
if(orderline.product.id == this.product.id && this.get_combo_prod_info()){
return false;
}
return result;
},
export_for_printing: function(){
var lines = _super_orderline.export_for_printing.call(this);
lines.combo_prod_info = this.get_combo_prod_info();
return lines;
},
get_display_price: function(){
var price = this.pos.config.iface_tax_included === 'total' ? this.get_price_with_tax() : this.get_base_price();
if (this.get_combo_prod_info()){
this.get_combo_prod_info().forEach(combo => price += combo['price']);
};
return price;
},
});
var POSComboProductPopup = PopupWidget.extend({
template: 'POSComboProductPopup',
events: _.extend({}, PopupWidget.prototype.events, {
'click .product': 'select_product',
}),
show: function(options){
var self = this;
self._super(options);
self.product = options.product || false;
self.combo_product_info = options.combo_product_info || false;
self.combo_products_details = [];
self.new_combo_products_details = [];
self.scroll_position = 0;
self.product.combo_category_ids.map(function(id){
var products = self.pos.db.get_product_by_category(id);
products.map(function(product){
self.combo_products_details.push(product);
})
});
this.renderElement();
},
select_product: function(event){
var self = this;
var products_info = [];
var $el = $(event.currentTarget);
var product_id = Number($el.data('product-id'));
var line_id = Number($el.data('line-id'));
var order = self.pos.get_order();
var selected_line = order.get_selected_orderline();
var price_list = self.pos.gui.screen_instances.products.product_list_widget._get_active_pricelist();
if(selected_line){
var product = self.pos.db.get_product_by_id(product_id);
var price = 0;
if(product){
price = product['combo_price'] != 0 ? product['combo_price'] : product.get_price(price_list, 1);
products_info.push({
'product':product,
'id':product_id,
'qty':1,
'price':price,
});
self.pos.get_order().add_product(product, {'price': price, 'extras': {'invisible': true} });
}
selected_line.set_combo_prod_info(products_info);
}else{
alert("Selected line not found!");
}
self.gui.close_popup();
},
click_cancel: function(){
this.gui.close_popup();
},
});
gui.define_popup({name:'combo_product_popup', widget: POSComboProductPopup});
});

51
pos_combinated_drinks/static/src/xml/pos.xml

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="POSComboProductPopup">
<div class="modal-dialog">
<div class="popup popup-textinput pos_combo_product_popup">
<p class="title">Combined product</p>
<div class="combo_product_container">
<t t-if="widget.combo_products_details">
<t t-foreach="widget.combo_products_details" t-as="record">
<div class="product"
t-att-data-categ-id="record.categ_id[0]"
t-att-data-product-id="record.id"
t-att-data-line-id="record.id">
<div class="products_list">
<t t-set="product" t-value="widget.pos.db.get_product_by_id(record.id)"/>
<div class="product-img">
<img t-att-src='widget.pos.gui.screen_instances.products.product_list_widget.get_product_image_url(product)'/>
</div>
<span class="price-tag">
<t t-esc="widget.format_currency(product.combo_price,'Product Price')"/>
</span>
<div class="product-name">
<t t-esc="record.display_name"/>
</div>
</div>
</div>
</t>
</t>
</div>
<div class="footer">
<div class="button cancel">
Cancel
</div>
</div>
</div>
</div>
</t>
<t t-extend="Orderline">
<t t-jquery="span.product-name" t-operation="append">
<t t-if="line.get_product().is_combo">
<t t-foreach="line.get_combo_prod_info()" t-as="prod_info">
<span>&#43;</span>
<t t-esc="prod_info.product.display_name"/>
</t>
</t>
</t>
</t>
</templates>

34
pos_combinated_drinks/views/point_of_sale.xml

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="package_product_template_only_form_view" model="ir.ui.view">
<field name="name">package.product.template.form.view</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='options']" position="inside">
<div>
<field name="is_combo"/>
<label for="is_combo"/>
</div>
</xpath>
<xpath expr="//div[@name='pricing']" position="after">
<field name="combo_price" class="oe_inline" widget='monetary'
options="{'currency_field': 'currency_id', 'field_digits': True}"/>
</xpath>
<xpath expr='//page[4]' position="after" >
<page string="Combo" attrs="{'invisible': [('is_combo', '=', False)]}">
<group>
<field name="combo_category_ids" widget="many2many_tags" string="Categories"/>
</group>
</page>
</xpath>
</field>
</record>
</data>
</odoo>

14
pos_combinated_drinks/views/pos_combined_drinks.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="enlarge_image index" name="pos_combinated_drinks assets" inherit_id="point_of_sale.index">
<xpath expr="." position="inside">
<script type="text/javascript" src="/pos_combinated_drinks/static/src/js/pos.js"></script>
<link rel="stylesheet" href="/pos_combinated_drinks/static/src/css/pos.css"/>
</xpath>
</template>
</data>
</odoo>
Loading…
Cancel
Save