[ADD] pos_sale_product_configurator: add optional products in the product info popup
With the module sale_product_configurator, you can add optionnal products on your product to suggest them during the sale process. We are now displaying them of the info popup of a product to easily find them in the POS, and we also allow to automatically open this popup for products having such optionnal products. closes odoo/odoo#71203 Task-id: 2518884 Signed-off-by: pimodoo <pimodoo@users.noreply.github.com>
This commit is contained in:
committed by
Pierre Masereel
parent
6e7450ac6a
commit
f11eb1dcca
@@ -172,7 +172,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 o_setting_box" >
|
||||
<div class="col-12 col-lg-6 o_setting_box" id="iface_big_scrollbars">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="iface_big_scrollbars"/>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
|
||||
{
|
||||
'name': 'pos_sale_product_configurator',
|
||||
'version': '1.0',
|
||||
'category': 'Hidden',
|
||||
'summary': 'Link module between point_of_sale and sale_product_configurator',
|
||||
'description': """
|
||||
This module adds features depending on both modules.
|
||||
""",
|
||||
'depends': ['point_of_sale', 'sale_product_configurator'],
|
||||
'installable': True,
|
||||
'auto_install': True,
|
||||
'data': [
|
||||
'views/pos_config_views.xml',
|
||||
],
|
||||
'assets': {
|
||||
'point_of_sale.assets': [
|
||||
'pos_sale_product_configurator/static/src/js/models.js',
|
||||
'pos_sale_product_configurator/static/src/css/popups/product_info_popup.css',
|
||||
],
|
||||
'web.assets_qweb': [
|
||||
'pos_sale_product_configurator/static/src/xml/**/*'
|
||||
]
|
||||
},
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import pos_config
|
||||
from . import product
|
||||
@@ -0,0 +1,7 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class PosConfig(models.Model):
|
||||
_inherit = 'pos.config'
|
||||
|
||||
iface_open_product_info = fields.Boolean(string="Open Product Info", help="Display the 'Product Info' page when a product with optional products are added in the customer cart")
|
||||
@@ -0,0 +1,26 @@
|
||||
from odoo import models
|
||||
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = 'product.product'
|
||||
|
||||
def get_product_info_pos(self, price, quantity, pos_config_id):
|
||||
res = super().get_product_info_pos(price, quantity, pos_config_id)
|
||||
|
||||
# Optional products
|
||||
res['optional_products'] = [
|
||||
{'name': p.name, 'price': min(p.product_variant_ids.mapped('lst_price'))}
|
||||
for p in self.optional_product_ids.filtered_domain(self._optional_product_pos_domain())
|
||||
]
|
||||
|
||||
return res
|
||||
|
||||
def has_optional_product_in_pos(self):
|
||||
self.ensure_one()
|
||||
return bool(self.optional_product_ids.filtered_domain(self._optional_product_pos_domain()))
|
||||
|
||||
def _optional_product_pos_domain(self):
|
||||
return [
|
||||
'&', '&', ['sale_ok', '=', True], ['available_in_pos', '=', True],
|
||||
'|', ['company_id', '=', self.env.company], ['company_id', '=', False]
|
||||
]
|
||||
@@ -0,0 +1,16 @@
|
||||
.product-info-popup .extra {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.product-info-popup .extra div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.product-info-popup .extra{
|
||||
flex-direction: column;
|
||||
}
|
||||
.product-info-popup .section-optional-product-body td {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
odoo.define('pos_sale_product_configurator.models', function (require) {
|
||||
"use strict";
|
||||
|
||||
const { Gui } = require('point_of_sale.Gui');
|
||||
var models = require('point_of_sale.models');
|
||||
|
||||
models.load_fields("product.product", ["optional_product_ids"]);
|
||||
models.load_fields("pos.config", ["iface_open_product_info"]);
|
||||
|
||||
const super_order_model = models.Order.prototype;
|
||||
models.Order = models.Order.extend({
|
||||
async add_product(product, options) {
|
||||
super_order_model.add_product.apply(this, arguments);
|
||||
if (this.pos.config.iface_open_product_info && product.optional_product_ids.length) {
|
||||
// The `optional_product_ids` only contains ids of the product templates and not the product itself
|
||||
// We don't load all the product template in the pos, so it'll be hard to know if the id comes from
|
||||
// a product available in POS. We send a quick cal to the back end to verify.
|
||||
const isProductLoaded = await this.pos.rpc(
|
||||
{
|
||||
model: 'product.product',
|
||||
method: 'has_optional_product_in_pos',
|
||||
args: [[product.id]]
|
||||
}
|
||||
);
|
||||
if (isProductLoaded) {
|
||||
Gui.showPopup('ProductInfoPopup', {product, quantity: this.get_selected_orderline().get_quantity()});
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="ProductInfoPopup" t-inherit="point_of_sale.ProductInfoPopup" t-inherit-mode="extension" owl="1">
|
||||
<xpath expr="//div[hasclass('extra')]" position="inside">
|
||||
<div class="section-optional-product" t-if="productInfo.optional_products.length > 0">
|
||||
<div class="section-title">
|
||||
<span>Optional Products</span>
|
||||
<div class="section-title-line"/>
|
||||
</div>
|
||||
<div class="section-optional-product-body">
|
||||
<table>
|
||||
<t t-foreach="productInfo.optional_products" t-as="optional" t-key="optional.name">
|
||||
<tr>
|
||||
<td><span class="searchable" t-esc="optional.name" t-on-click="searchProduct(optional.name)"/></td>
|
||||
<td class="table-value">
|
||||
from <t t-esc="env.pos.format_currency(optional.price)"/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="pos_config_view_form" model="ir.ui.view">
|
||||
<field name="name">pos.config.form.view.inherit.pos.sale.product.configuration</field>
|
||||
<field name="model">pos.config</field>
|
||||
<field name="inherit_id" ref="point_of_sale.pos_config_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<div id="iface_big_scrollbars" position="after">
|
||||
<div class="col-12 col-lg-6 o_setting_box" id="iface_open_product_info">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="iface_open_product_info"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="iface_open_product_info"/>
|
||||
<div class="text-muted">
|
||||
Display the 'Product Info' page when a product with optional products are added in the customer cart
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user