Browse Source

Merge 4bf73b7a42 into ad79aa45cf

pull/630/merge
Florent de Labarre 5 years ago
committed by GitHub
parent
commit
134d3a8730
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      setup/web_product_variante_selector/odoo/__init__.py
  2. 1
      setup/web_product_variante_selector/odoo/addons/__init__.py
  3. 1
      setup/web_product_variante_selector/odoo/addons/web_product_variante_selector
  4. 6
      setup/web_product_variante_selector/setup.py
  5. 81
      web_product_variante_selector/README.rst
  6. 3
      web_product_variante_selector/__init__.py
  7. 17
      web_product_variante_selector/__manifest__.py
  8. BIN
      web_product_variante_selector/static/description/description/img_1.png
  9. BIN
      web_product_variante_selector/static/description/description/img_2.png
  10. BIN
      web_product_variante_selector/static/description/icon.png
  11. 207
      web_product_variante_selector/static/src/js/form_common.js
  12. 10
      web_product_variante_selector/views/web_product_variante_selector.xml
  13. 3
      web_product_variante_selector/wizard/__init__.py
  14. 145
      web_product_variante_selector/wizard/wizard_product_variante_selector.py
  15. 100
      web_product_variante_selector/wizard/wizard_product_variante_selector.xml

1
setup/web_product_variante_selector/odoo/__init__.py

@ -0,0 +1 @@
__import__('pkg_resources').declare_namespace(__name__)

1
setup/web_product_variante_selector/odoo/addons/__init__.py

@ -0,0 +1 @@
__import__('pkg_resources').declare_namespace(__name__)

1
setup/web_product_variante_selector/odoo/addons/web_product_variante_selector

@ -0,0 +1 @@
../../../../web_product_variante_selector

6
setup/web_product_variante_selector/setup.py

@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)

81
web_product_variante_selector/README.rst

@ -0,0 +1,81 @@
.. 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
=============================
Web product Variante Selector
=============================
This module extends the functionality of search widget to support product with lot of variantes.
.. image:: /web_product_variante_selector/static/description/img_1.png
:alt: Screenshot
.. image:: /web_product_variante_selector/static/description/img_2.png
:alt: Screenshot
In each field Many2one with 'product.product' as comodel, under "Search More" and "Create and Edit", you can see "Product Variante Selector".
You can add 'no_select_variante': True in options attribute in xml view to desactivate this function localy.
Limitation at 10 attributes per product.
Installation
============
To install this module, you need to:
#. Just install, no configuration needed
Configuration
=============
To configure this module, you need to:
#. No configuration needed
Usage
=====
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/162/10.0
Known issues / Roadmap
======================
* Inscrease the limitation.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/web/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smash it by providing detailed and welcomed feedback.
Credits
=======
Images
------
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
Contributors
------------
* Florent de Labarre
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.

3
web_product_variante_selector/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import wizard

17
web_product_variante_selector/__manifest__.py

@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
{
'name': 'Web product variante selector',
'version': '10.0.1.0.0',
'license': 'AGPL-3',
'author': "Florent de Labarre, Odoo Community Association (OCA)",
'website': 'https://github.com/fmdl',
'summary': 'Web product variante selector',
'category': 'Product',
'depends': ['product', 'web', ],
'data': [
'views/web_product_variante_selector.xml',
'wizard/wizard_product_variante_selector.xml',
],
'installable': True,
}

BIN
web_product_variante_selector/static/description/description/img_1.png

After

Width: 1065  |  Height: 510  |  Size: 37 KiB

BIN
web_product_variante_selector/static/description/description/img_2.png

After

Width: 325  |  Height: 341  |  Size: 18 KiB

BIN
web_product_variante_selector/static/description/icon.png

After

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

207
web_product_variante_selector/static/src/js/form_common.js

@ -0,0 +1,207 @@
odoo.define('web_product_variante_selector.form_common_extended', function(require) {
"use strict";
var FormCommon = require('web.form_common');
var core = require('web.core');
var data = require('web.data');
var data_manager = require('web.data_manager');
var _t = core._t;
var form_relational = require('web.form_relational')
var ViewDialog = FormCommon.ViewDialog;
form_relational.FieldMany2One.include({
_search_variante: function(view, ids, context) {
var self = this;
var current_product_id = 0;
if (!(self.current_display === '')) {
var product_ids = self.display_value;
for (var product_id in product_ids) {
current_product_id = parseInt(product_id);
break;
}
}
new SelectProductVariante(this, _.extend({}, (this.options || {}), {
res_model: "web.product.variante.selector",
domain: self.build_domain(),
target: "new",
context: {
'select_variante_domain': self.build_domain().eval(),
'current_product_id': current_product_id
},
title: _t("Product Variante Selector"),
initial_ids: ids ? _.map(ids, function(x) {
return x[0];
}) : undefined,
initial_view: "form",
on_selected: function(element_ids) {
self.add_id(element_ids[0]);
self.focus();
}
})).open();
},
get_search_result: function(search_val) {
var self = this;
var dataset = new data.DataSet(this, this.field.relation, self.build_context());
this.last_query = search_val;
var exclusion_domain = [],
ids_blacklist = this.get_search_blacklist();
if (!_(ids_blacklist).isEmpty()) {
exclusion_domain.push(['id', 'not in', ids_blacklist]);
}
return this.orderer.add(dataset.name_search(
search_val, new data.CompoundDomain(self.build_domain(), exclusion_domain),
'ilike', this.limit + 1, self.build_context())).then(function(_data) {
self.last_search = _data;
// possible selections for the m2o
var values = _.map(_data, function(x) {
x[1] = x[1].split("\n")[0];
return {
label: _.str.escapeHTML(x[1].trim()) || data.noDisplayContent,
value: x[1],
name: x[1],
id: x[0],
};
});
// search more... if more results that max
if (values.length > self.limit) {
values = values.slice(0, self.limit);
values.push({
label: _t("Search More..."),
action: function() {
dataset.name_search(search_val, self.build_domain(), 'ilike', 160).done(function(_data) {
self._search_create_popup("search", _data);
});
},
classname: 'o_m2o_dropdown_option'
});
}
// quick create
var raw_result = _(_data.result).map(function(x) {
return x[1];
});
if (search_val.length > 0 && !_.include(raw_result, search_val) &&
!(self.options && (self.options.no_create || self.options.no_quick_create))) {
self.can_create && values.push({
label: _.str.sprintf(_t('Create "<strong>%s</strong>"'),
$('<span />').text(search_val).html()),
action: function() {
self._quick_create(search_val);
},
classname: 'o_m2o_dropdown_option'
});
}
// create...
if (!(self.options && (self.options.no_create || self.options.no_create_edit)) && self.can_create) {
values.push({
label: _t("Create and Edit..."),
action: function() {
self._search_create_popup("form", undefined, self._create_context(search_val));
},
classname: 'o_m2o_dropdown_option'
});
} else if (values.length === 0) {
values.push({
label: _t("No results to show..."),
action: function() {},
classname: 'o_m2o_dropdown_option'
});
}
// select variante
if (self.field.relation === "product.product" && !((self.options && self.options.no_select_variante))) {
values.push({
label: _t("Variante Selector..."),
action: function() {
self._search_variante("form", _data);
},
classname: 'o_m2o_dropdown_option'
});
}
return values;
});
},
});
/**
* Variante Selector (displays a form view record and leave once saved)
*/
var SelectProductVariante = ViewDialog.extend({
init: function(parent, options) {
var self = this;
if (!options || !options.buttons) {
options = options || {};
options.buttons = [{
text: _t("Discard"),
classes: "btn-default o_form_button_cancel",
close: true,
click: function() {
self.view_form.trigger('on_button_cancel');
}
}];
options.buttons.splice(0, 0, {
text: _t("Select"),
classes: "btn-primary",
click: function() {
var product_ids = self.view_form.fields.product_id.display_value
for (var product_id in product_ids) {
self.on_selected([parseInt(product_id)]);
self.close();
break;
}
}
});
}
this._super(parent, options);
},
open: function() {
var self = this;
var _super = this._super.bind(this);
this.init_dataset();
if (this.res_id) {
this.dataset.ids = [this.res_id];
this.dataset.index = 0;
} else {
this.dataset.index = null;
}
var options = _.clone(this.options.form_view_options) || {};
if (this.res_id !== null) {
options.initial_mode = this.options.readonly ? "view" : "edit";
}
_.extend(options, {
$buttons: this.$buttons,
});
var FormView = core.view_registry.get('form');
var fields_view_def;
if (this.options.alternative_form_view) {
fields_view_def = $.when(this.options.alternative_form_view);
} else {
fields_view_def = data_manager.load_fields_view(this.dataset, this.options.view_id, 'form', false);
}
fields_view_def.then(function(fields_view) {
self.view_form = new FormView(self, self.dataset, fields_view, options);
var fragment = document.createDocumentFragment();
self.view_form.appendTo(fragment).then(function() {
self.view_form.do_show().then(function() {
_super().$el.append(fragment);
self.view_form.autofocus();
});
});
});
return this;
},
});
return {
SelectProductVariante: SelectProductVariante,
};
});

10
web_product_variante_selector/views/web_product_variante_selector.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="assets_backend" name="web_product_variante_selector" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/web_product_variante_selector/static/src/js/form_common.js"></script>
</xpath>
</template>
</data>
</odoo>

3
web_product_variante_selector/wizard/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import wizard_product_variante_selector

145
web_product_variante_selector/wizard/wizard_product_variante_selector.py

@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-
from odoo import models, api, fields
class WizardSelectVariante(models.TransientModel):
_name = 'web.product.variante.selector'
_description = 'Select Product Variante'
product_tmpl_id = fields.Many2one('product.template', 'Product', )
product_id = fields.Many2one('product.product', 'Product Variante',
default=lambda self:
self.env['product.product'].browse(
self.env.context.get(
'current_product_id', False)).id)
stop_update = fields.Boolean('Stop_update',
default=lambda self:
False if self.env.context.get(
'current_product_id', False)
else True, readonly=True)
attr_0 = fields.Many2one(
'product.attribute', string='Attribute', readonly=1)
value_0 = fields.Many2one('product.attribute.value', string='Value')
attr_1 = fields.Many2one(
'product.attribute', string='Attribute', readonly=1)
value_1 = fields.Many2one('product.attribute.value', string='Value')
attr_2 = fields.Many2one(
'product.attribute', string='Attribute', readonly=1)
value_2 = fields.Many2one('product.attribute.value', string='Value')
attr_3 = fields.Many2one(
'product.attribute', string='Attribute', readonly=1)
value_3 = fields.Many2one('product.attribute.value', string='Value')
attr_4 = fields.Many2one(
'product.attribute', string='Attribute', readonly=1)
value_4 = fields.Many2one('product.attribute.value', string='Value')
attr_5 = fields.Many2one(
'product.attribute', string='Attribute', readonly=1)
value_5 = fields.Many2one('product.attribute.value', string='Value')
attr_6 = fields.Many2one(
'product.attribute', string='Attribute', readonly=1)
value_6 = fields.Many2one('product.attribute.value', string='Value')
attr_7 = fields.Many2one(
'product.attribute', string='Attribute', readonly=1)
value_7 = fields.Many2one('product.attribute.value', string='Value')
attr_8 = fields.Many2one(
'product.attribute', string='Attribute', readonly=1)
value_8 = fields.Many2one('product.attribute.value', string='Value')
attr_9 = fields.Many2one(
'product.attribute', string='Attribute', readonly=1)
value_9 = fields.Many2one('product.attribute.value', string='Value')
@api.onchange('product_id')
def on_change_product_id(self):
res = {}
dom = {}
vals = {}
if self.product_id and not self.stop_update:
vals.update(
{'product_tmpl_id': self.product_id.product_tmpl_id.id,
'stop_update': True})
dom.update({'product_id': self.env.context.get(
'select_variante_domain', [])})
attributes = self.product_id.product_tmpl_id.attribute_line_ids
for i in range(0, 10):
if i < len(attributes):
current_value = self.product_id.attribute_value_ids & \
attributes[i].value_ids
vals.update({'attr_%s' % i:
attributes[i].attribute_id.id,
'value_%s' % i:
current_value[0].id
if current_value else False})
dom.update(
{'value_%s' % i:
[('id', 'in', attributes[i].value_ids.ids)]})
else:
vals.update({'attr_%s' % i: False})
vals.update({'value_%s' % i: False})
res.update({'value': vals, 'domain': dom, })
return res
@api.onchange('product_tmpl_id')
def on_change_product_tmpl_id(self):
res = {}
dom = {}
vals = {}
domain = []
domain.extend(self.env.context.get('select_variante_domain', []))
if self.stop_update or (not self.stop_update and not self.product_id):
if self.product_tmpl_id:
domain.append(
('product_tmpl_id', '=', self.product_tmpl_id.id))
vals.update(
{'product_id': self.product_id.search(domain, limit=1).id})
dom.update({'product_id': domain})
attributes = self.product_tmpl_id.attribute_line_ids
for i in range(0, 10):
vals.update({'value_%s' % i: False})
if i < len(attributes):
vals.update({'attr_%s' % i:
attributes[i].attribute_id.id})
dom.update(
{'value_%s' % i:
[('id', 'in', attributes[i].value_ids.ids)]})
else:
vals.update({'attr_%s' % i: False})
else:
vals.update({'product_id': False, })
for i in range(0, 10):
vals.update({'attr_%s' % i: False, 'value_%s' % i: False})
res.update({'value': vals, 'domain': dom, })
return res
@api.onchange('value_0',
'value_1',
'value_2',
'value_3',
'value_4',
'value_5',
'value_6',
'value_7',
'value_8',
'value_9')
def onchange_value(self):
res = {}
values = []
domain = self.env.context.get('select_variante_domain', [])
for i in range(0, 10):
value = self['value_%s' % i]
if value:
values.extend((value.attribute_id.value_ids - value).ids)
dom = []
dom.extend(domain)
dom.append(('product_tmpl_id', '=', self.product_tmpl_id.id))
if values:
dom.append(('attribute_value_ids', 'not in', values))
res_ids = self.product_id.search(dom).ids
res.update({'value': {'product_id': res_ids[0] if res_ids else False}})
domain.append(('id', 'in', res_ids))
res.update({'domain': {'product_id': domain}})
return res

100
web_product_variante_selector/wizard/wizard_product_variante_selector.xml

@ -0,0 +1,100 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="wizard_select_variante_form" model="ir.ui.view">
<field name="name">web.product.variante.selector.form</field>
<field name="model">web.product.variante.selector</field>
<field eval="20" name="priority"/>
<field name="arch" type="xml">
<form string="Wizard">
<group>
<field name="product_tmpl_id" options="{'no_create': True}" string="Select a product"/>
<field name="product_id" options="{'no_create': True, 'no_select_variante': True}" attrs="{'invisible':[('product_tmpl_id', '=', False), ('product_id', '=', False)]}"/>
<field name="stop_update" invisible="1"/>
</group>
<group attrs="{'invisible':[('attr_0', '=', False)]}" col="2">
<group>
<field name="attr_0"/>
</group>
<group>
<field name="value_0" domain="[('attribute_id', '=', attr_0)]" options="{'no_create': True}"/>
</group>
</group>
<group attrs="{'invisible':[('attr_1', '=', False)]}" col="2">
<group>
<field name="attr_1"/>
</group>
<group>
<field name="value_1" domain="[('attribute_id', '=', attr_1)]" options="{'no_create': True}"/>
</group>
</group>
<group attrs="{'invisible':[('attr_2', '=', False)]}" col="2">
<group>
<field name="attr_2"/>
</group>
<group>
<field name="value_2" domain="[('attribute_id', '=', attr_2)]" options="{'no_create': True}"/>
</group>
</group>
<group attrs="{'invisible':[('attr_3', '=', False)]}" col="2">
<group>
<field name="attr_3"/>
</group>
<group>
<field name="value_3" domain="[('attribute_id', '=', attr_3)]" options="{'no_create': True}"/>
</group>
</group>
<group attrs="{'invisible':[('attr_4', '=', False)]}" col="2">
<group>
<field name="attr_4"/>
</group>
<group>
<field name="value_4" domain="[('attribute_id', '=', attr_4)]" options="{'no_create': True}"/>
</group>
</group>
<group attrs="{'invisible':[('attr_5', '=', False)]}" col="2">
<group>
<field name="attr_5"/>
</group>
<group>
<field name="value_5" domain="[('attribute_id', '=', attr_5)]" options="{'no_create': True}"/>
</group>
</group>
<group attrs="{'invisible':[('attr_6', '=', False)]}" col="2">
<group>
<field name="attr_6"/>
</group>
<group>
<field name="value_6" domain="[('attribute_id', '=', attr_6)]" options="{'no_create': True}"/>
</group>
</group>
<group attrs="{'invisible':[('attr_7', '=', False)]}" col="2">
<group>
<field name="attr_7"/>
</group>
<group>
<field name="value_7" domain="[('attribute_id', '=', attr_7)]" options="{'no_create': True}"/>
</group>
</group>
<group attrs="{'invisible':[('attr_8', '=', False)]}" col="2">
<group>
<field name="attr_8"/>
</group>
<group>
<field name="value_8" domain="[('attribute_id', '=', attr_8)]" options="{'no_create': True}"/>
</group>
</group>
<group attrs="{'invisible':[('attr_9', '=', False)]}" col="2">
<group>
<field name="attr_9"/>
</group>
<group>
<field name="value_9" domain="[('attribute_id', '=', attr_9)]" options="{'no_create': True}"/>
</group>
</group>
</form>
</field>
</record>
</data>
</odoo>
Loading…
Cancel
Save