[IMP] point_of_sale: allow to choose loaded categs
Before this commit, it was not possible to effectively limit the available products when a company had several POS with different product offers. This commit allows limiting the available product categories for a single POS. Now, a company can serve different POS with different product offerings. Anecdotal Note: This was especially annoying as the POS only shows 100 products. If those happened to be the products not served by a signle POS, the only work around was using the search bar (on a tablet?!?) closes odoo/odoo#28393
This commit is contained in:
committed by
Gert Pellin
parent
9215a40768
commit
30e4d89a62
@@ -63,6 +63,13 @@ class PosConfig(models.Model):
|
||||
def _compute_default_customer_html(self):
|
||||
return self.env['ir.qweb'].render('point_of_sale.customer_facing_display_html')
|
||||
|
||||
@api.depends('limit_categories', 'iface_available_categ_ids')
|
||||
def _compute_iface_start_categ_domain_ids(self):
|
||||
if self.limit_categories:
|
||||
self.iface_start_categ_domain_ids = self.iface_available_categ_ids
|
||||
else:
|
||||
self.iface_start_categ_domain_ids = self.env['pos.category'].search([])
|
||||
|
||||
name = fields.Char(string='Point of Sale Name', index=True, required=True, help="An internal identification of the point of sale.")
|
||||
is_installed_account_accountant = fields.Boolean(string="Is the Full Accounting Installed",
|
||||
compute="_compute_is_installed_account_accountant")
|
||||
@@ -103,6 +110,10 @@ class PosConfig(models.Model):
|
||||
iface_tax_included = fields.Selection([('subtotal', 'Tax-Excluded Price'), ('total', 'Tax-Included Price')], string="Tax Display", default='subtotal', required=True)
|
||||
iface_start_categ_id = fields.Many2one('pos.category', string='Initial Category',
|
||||
help='The point of sale will display this product category by default. If no category is specified, all available products will be shown.')
|
||||
iface_available_categ_ids = fields.Many2many('pos.category', string='Available Category Tree',
|
||||
help='The point of sale will only display products which are within one of the selected category trees. If no category is specified, all available products will be shown')
|
||||
iface_start_categ_domain_ids = fields.Many2many('pos.category', compute='_compute_iface_start_categ_domain_ids', store=False,
|
||||
help='Technical field used as a domain for iface_start_categ_id.')
|
||||
iface_display_categ_images = fields.Boolean(string='Display Category Pictures',
|
||||
help="The product categories will be displayed with pictures.")
|
||||
restrict_price_control = fields.Boolean(string='Restrict Price Modifications to Managers',
|
||||
@@ -154,6 +165,7 @@ class PosConfig(models.Model):
|
||||
tax_regime = fields.Boolean("Tax Regime")
|
||||
tax_regime_selection = fields.Boolean("Tax Regime Selection value")
|
||||
start_category = fields.Boolean("Set Start Category")
|
||||
limit_categories = fields.Boolean("Restrict Available Product Categories")
|
||||
module_account = fields.Boolean(string='Invoicing', help='Enables invoice generation from the Point of Sale.')
|
||||
module_pos_restaurant = fields.Boolean("Is a Bar/Restaurant")
|
||||
module_pos_discount = fields.Boolean("Global Discounts")
|
||||
@@ -307,6 +319,13 @@ class PosConfig(models.Model):
|
||||
if not self.start_category:
|
||||
self.iface_start_categ_id = False
|
||||
|
||||
@api.onchange('limit_categories', 'iface_available_categ_ids', 'iface_start_categ_id')
|
||||
def _onchange_limit_categories(self):
|
||||
if not self.limit_categories:
|
||||
self.iface_available_categ_ids = False
|
||||
elif self.iface_start_categ_id not in self.iface_available_categ_ids:
|
||||
self.iface_start_categ_id = False
|
||||
|
||||
@api.onchange('is_header_or_footer')
|
||||
def _onchange_header_footer(self):
|
||||
if not self.is_header_or_footer:
|
||||
|
||||
@@ -94,19 +94,20 @@ var PosDB = core.Class.extend({
|
||||
name : 'Root',
|
||||
};
|
||||
}
|
||||
for(var i=0, len = categories.length; i < len; i++){
|
||||
this.category_by_id[categories[i].id] = categories[i];
|
||||
}
|
||||
len = categories.length;
|
||||
for(i=0; i < len; i++){
|
||||
var cat = categories[i];
|
||||
var parent_id = cat.parent_id[0] || this.root_category_id;
|
||||
this.category_parent[cat.id] = cat.parent_id[0];
|
||||
if(!this.category_childs[parent_id]){
|
||||
this.category_childs[parent_id] = [];
|
||||
categories.forEach(function(cat){
|
||||
self.category_by_id[cat.id] = cat;
|
||||
});
|
||||
categories.forEach(function(cat){
|
||||
var parent_id = cat.parent_id[0];
|
||||
if(!(parent_id && self.category_by_id[parent_id])){
|
||||
parent_id = self.root_category_id;
|
||||
}
|
||||
this.category_childs[parent_id].push(cat.id);
|
||||
}
|
||||
self.category_parent[cat.id] = parent_id;
|
||||
if(!self.category_childs[parent_id]){
|
||||
self.category_childs[parent_id] = [];
|
||||
}
|
||||
self.category_childs[parent_id].push(cat.id);
|
||||
});
|
||||
function make_ancestors(cat_id, ancestors){
|
||||
self.category_ancestors[cat_id] = ancestors;
|
||||
|
||||
|
||||
@@ -355,7 +355,9 @@ exports.PosModel = Backbone.Model.extend({
|
||||
},{
|
||||
model: 'pos.category',
|
||||
fields: ['id', 'name', 'parent_id', 'child_id'],
|
||||
domain: null,
|
||||
domain: function(self) {
|
||||
return self.config.limit_categories ? [['id', 'in', self.config.iface_available_categ_ids]] : [];
|
||||
},
|
||||
loaded: function(self, categories){
|
||||
self.db.add_categories(categories);
|
||||
},
|
||||
@@ -365,7 +367,13 @@ exports.PosModel = Backbone.Model.extend({
|
||||
'barcode', 'default_code', 'to_weight', 'uom_id', 'description_sale', 'description',
|
||||
'product_tmpl_id','tracking'],
|
||||
order: _.map(['sequence','default_code','name'], function (name) { return {name: name}; }),
|
||||
domain: [['sale_ok','=',true],['available_in_pos','=',true]],
|
||||
domain: function(self){
|
||||
var domain = [['sale_ok','=',true],['available_in_pos','=',true]];
|
||||
if (self.config.limit_categories) {
|
||||
domain.push(['pos_categ_id', 'in', self.config.iface_available_categ_ids]);
|
||||
}
|
||||
return domain;
|
||||
},
|
||||
context: function(self){ return { display_default_code: false }; },
|
||||
loaded: function(self, products){
|
||||
var using_company_currency = self.config.currency_id[0] === self.company.currency_id[0];
|
||||
@@ -1326,7 +1334,12 @@ exports.Orderline = Backbone.Model.extend({
|
||||
this.pos = options.pos;
|
||||
this.order = options.order;
|
||||
if (options.json) {
|
||||
this.init_from_JSON(options.json);
|
||||
try {
|
||||
this.init_from_JSON(options.json);
|
||||
} catch(error) {
|
||||
console.error('ERROR: attempting to recover product ID', json.product_id,
|
||||
'not available in the point of sale. Correct the product or clean the browser cache.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.product = options.product;
|
||||
@@ -1347,10 +1360,6 @@ exports.Orderline = Backbone.Model.extend({
|
||||
},
|
||||
init_from_JSON: function(json) {
|
||||
this.product = this.pos.db.get_product_by_id(json.product_id);
|
||||
if (!this.product) {
|
||||
console.error('ERROR: attempting to recover product ID', json.product_id,
|
||||
'not available in the point of sale. Correct the product or clean the browser cache.');
|
||||
}
|
||||
this.set_product_lot(this.product);
|
||||
this.price = json.price_unit;
|
||||
this.set_discount(json.discount);
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 o_setting_box" >
|
||||
<field name="iface_start_categ_domain_ids" invisible="1"/>
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="start_category"/>
|
||||
</div>
|
||||
@@ -82,7 +83,21 @@
|
||||
Start selling from a default product category
|
||||
</div>
|
||||
<div class="content-group mt16" attrs="{'invisible': [('start_category', '=', False)]}">
|
||||
<field name="iface_start_categ_id"/>
|
||||
<field name="iface_start_categ_id" domain="[('id', 'in', iface_start_categ_domain_ids)]"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 o_setting_box" >
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="limit_categories"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="limit_categories"/>
|
||||
<div class="text-muted">
|
||||
Available Product Categories
|
||||
</div>
|
||||
<div class="content-group mt16" attrs="{'invisible': [('limit_categories', '=', False)]}">
|
||||
<field name="iface_available_categ_ids" widget="many2many_tags"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user