Browse Source

[WIP]

pull/129/head
Sylvain LE GAL 8 years ago
parent
commit
3044bfe9e3
  1. 115
      barcodes_generate/README.rst
  2. 49
      barcodes_generate/__openerp__.py
  3. 25
      barcodes_generate/demo/barcode.rule.xml
  4. 26
      barcodes_generate/demo/barcode_rule.xml
  5. 12
      barcodes_generate/demo/res_users.xml
  6. 118
      barcodes_generate/models/barcode_generate_mixin.py
  7. 28
      barcodes_generate/models/barcode_rule.py
  8. 5
      barcodes_generate/models/product_product.py
  9. 4
      barcodes_generate/models/res_partner.py
  10. 5
      barcodes_generate/security/res_groups.xml
  11. BIN
      barcodes_generate/static/description/barcode_rule_form.png
  12. 0
      barcodes_generate/static/description/barcode_rule_tree.png
  13. BIN
      barcodes_generate/static/description/product_product_form_empty.png
  14. BIN
      barcodes_generate/static/description/product_product_form_generated.png
  15. 5
      barcodes_generate/views/view_barcode_rule.xml
  16. 25
      barcodes_generate/views/view_product_product.xml
  17. 25
      barcodes_generate/views/view_res_partner.xml

115
barcodes_generate/README.rst

@ -0,0 +1,115 @@
.. 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
==============
{module_title}
==============
============================================
Generate Barcodes for Products and Customers
============================================
This module expends Odoo functionnality, allowing user to generate barcode
depending on a given barcode rule.
For exemple, a typical pattern for products is "23.....{NNNDD}" that means
that:
* the EAN13 code will begin by '23' ;
* followed by 5 digits (named Barcode Base in this module, ) ;
* and after 5 others digits to define the variable price ;
* a 13 digit control
With this module, it is possible to:
* Affect a pattern (barcode.rule) to a product.product or a res.partner
* Generate the next Barcode base of a pattern. (to avoid duplicate barcode)
* Generate a barcode, based on a pattern and a barcode base
Configuration
=============
To configure this module, you need to:
* Go to Point Of Sale / Configuration / Barcode Nomenclatures and select
* Select a Nomenclature
* Create or select a rule
.. figure:: barcodes_generate/static/description/barcode_rule_tree.png
* Check 'Available for Products', or 'Available for Partners' Checkbox.
.. figure:: barcodes_generate/static/description/barcode_rule_form.png
Usage
=====
To use this module, you need to:
* Go to a Product form (or a Partner Form):
* set a rule to the current object
.. figure:: barcodes_generate/static/description/product_product_form_empty.png
* Click on 'Generate Base and Barcode'
.. figure:: barcodes_generate/static/description/product_product_form_generated.png
Alternatively you can set manually a barcode base, and click only on Generate barcode.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/184/9.0
Known issues / Roadmap
======================
Dependency to point_of_sale is required because barcode field, defined in 'base'
module (in the res.partner model), is defined in a 'point_of_sale' view.
Furthermore, barcode nomenclature menu is available on Point Of Sale submenu.
It's a relative problem, because product barcodes generation will occures
mostly in a Point of Sale context.
You could comment 'point_of_sale' dependencies if you want to use this module
without point of sale installed.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/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
=======
Images
------
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
* Icon of the module is based on the Oxygen Team work and is under LGPL licence:
http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org.html
Contributors
------------
* Sylvain LE GAL (https://twitter.com/legalsylvain)
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.

49
barcodes_generate/__openerp__.py

@ -1,51 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016-Today GRAP (http://www.grap.coop)
# Copyright (C) 2016-Today GRAP (http://www.lalouve.net)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
'name': 'Barcodes - Generate',
'summary': 'Generate Barcodes for Products and Customers',
'name': 'Generate Barcodes',
'summary': 'Generate Barcodes for Products and Partners',
'version': '1.0',
'category': 'Point Of Sale',
'description': """
============================================
Generate Barcodes for Products and Customers
============================================
This module expends Odoo functionnality, allowing user to generate barcode
depending on a given barcode rule.
For exemple, a typical pattern for products is "23.....{NNNDD}" that means
that the EAN13 code will begin by '23', followed by 5 digits and after 5 others
digits to define the variable price. (EAN13 has a third char for control).
With this module, it is possible to:
* Affect a pattern (barcode.rule) to a product.product or a res.partner
* To generate an EAN13 depending on the defined pattern and a custom ID
Note
----
Dependency to point_of_sale is required because barcode field, defined in 'base'
module (in the res.partner model), is defined in a 'point_of_sale' view.
It's a relative problem, because product barcodes generation will occures
mostly in a Point of Sale context.
You could comment 'point_of_sale' dependency if you want to use this module
without point of sale.
Copyright Note
--------------
Icon of the module is based on the Oxygen Team work and is under LGPL licence:
http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org.html
""",
'author': 'GRAP',
'website': 'http://www.grap.coop',
'author':
'GRAP,'
'La Louve,'
'Odoo Community Association (OCA)',
'website': 'http://www.odoo-community.org',
'license': 'AGPL-3',
'depends': [
'barcodes',
@ -59,6 +27,7 @@ http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org.html
],
'demo': [
'demo/res_users.xml',
'demo/barcode_rule.xml',
],
'images': [
'static/description/barcode_rule.png'

25
barcodes_generate/demo/barcode.rule.xml

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016-Today: GRAP (http://www.grap.coop)
Copyright (C) 2016-Today GRAP (http://www.lalouve.net)
@author Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="point_of_sale.barcode_rule_price_two_dec" model="barcode.rule">
<field name="is_product_available" eval="True" />
</record>
<record id="partner_generated_barcode" model="barcode.rule">
<field name="name">Partner (Generated Barcode)</field>
<field name="is_partner_available" eval="True" />
<field name="type">client</field>
<field name="encoding">ean13</field>
<field name="encoding">042.........</field>
<field name="sequence">999</field>
</record>
</odoo>

26
barcodes_generate/demo/barcode_rule.xml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016-Today: GRAP (http://www.grap.coop)
Copyright (C) 2016-Today GRAP (http://www.lalouve.net)
@author Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="point_of_sale.barcode_rule_price_two_dec" model="barcode.rule">
<field name="is_product_available" eval="True" />
</record>
<record id="partner_generated_barcode" model="barcode.rule">
<field name="name">Partner (Generated Barcode)</field>
<field name="barcode_nomenclature_id" ref="barcodes.default_barcode_nomenclature"/>
<field name="is_partner_available" eval="True" />
<field name="type">client</field>
<field name="encoding">ean13</field>
<field name="pattern">042.........</field>
<field name="sequence">999</field>
</record>
</odoo>

12
barcodes_generate/demo/res_users.xml

@ -1,13 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016-Today: GRAP (http://www.grap.coop)
Copyright (C) 2016-Today GRAP (http://www.lalouve.net)
@author Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<openerp><data>
<odoo>
<record id="base.user_root" model="res.users">
<field name="groups_id" eval="[(4, ref('barcodes_generate.generate_product_barcode')), (4, ref('barcodes_generate.generate_partner_barcode'))]" />
<field name="groups_id" eval="[
(4, ref('barcodes_generate.generate_product_barcode')),
(4, ref('barcodes_generate.generate_partner_barcode')),
(4, ref('product.group_product_variant')),
]" />
</record>
</data></openerp>
</odoo>

118
barcodes_generate/models/barcode_generate_mixin.py

@ -1,53 +1,99 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2014 GRAP (http://www.grap.coop)
# Copyright (C) 2016-Today GRAP (http://www.lalouve.net)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import barcode
from openerp.osv import fields
from openerp.osv.orm import AbstractModel
from openerp import models, fields, api, exceptions
class barcode_generate_mixin(AbstractModel):
class barcode_generate_mixin(models.AbstractModel):
_name = 'barcode.generate.mixin'
_columns = {
'barcode_rule_id': fields.many2one(
'barcode.rule', 'Barcode Rule'),
'barcode_base': fields.integer('Barcode Base'),
}
def generate_barcode(self, cr, uid, ids, context=None):
vals = self._compute_custom_barcode(cr, uid, ids, context=context)
for id in vals.keys():
self.write(cr, uid, id, {'ean13': vals[id]}, context=context)
return True
def _compute_custom_barcode(self, cr, uid, ids, context=None):
res = {}
for item in self.browse(cr, uid, ids, context=context):
if item.barcode_rule_id and item.barcode_base:
pass
barcode_class = barcode.get_barcode_class(
item.barcode_rule_id.encoding)
# Column Section
barcode_rule_id = fields.Many2one(
string='Barcode Rule', comodel_name='barcode.rule')
barcode_base = fields.Char(string='Barcode Base')
# Constrains Section
@api.multi
@api.constrains('barcode_base')
def _constrains_barcode_base(self):
for item in self:
if item.barcode_base and not item.barcode_base.isdigit():
raise exceptions.Warning(_("Barcode Base should be numeric"))
# View Section
@api.multi
def generate_base(self):
for item in self:
padding = item.barcode_rule_id.pattern.count('.')
generic_code = self._get_custom_barcode(item)
if generic_code:
generic_code = generic_code.replace(
'.' * padding, '_' * padding)
reserved_barcodes = self.search([('barcode', 'ilike', generic_code)]).mapped('barcode')
next_base = str(self._get_next_integer_base(
item, generic_code, reserved_barcodes)).rjust(padding, '0')
item.barcode_base = next_base
@api.multi
def generate_barcode(self):
for item in self:
padding = item.barcode_rule_id.pattern.count('.')
full_base = str(item.barcode_base).rjust(padding, '0')
custom_code = self._get_custom_barcode(item)
if custom_code:
custom_code = custom_code.replace('.' * padding, full_base)
barcode_class = barcode.get_barcode_class(
item.barcode_rule_id.encoding)
item.barcode = barcode_class(custom_code)
@api.multi
def generate_base_barcode(self):
for item in self:
if not item.barcode_base:
item.generate_base()
item.generate_barcode()
# Custom Section
@api.model
def _get_next_integer_base(self, item, generic_code, reserved_barcodes):
"""Given a list of reserved_barcodes, This will return the next"
base barcode. By default, return the max barcode base + 1.
Overload / Overwrite this function to provide custom behaviour.
(specially, fill gaps functionnality).
generic_code should have the '_' pattern.
"""
if not reserved_barcodes:
return 1
max_barcode = sorted(reserved_barcodes)[len(reserved_barcodes) - 1]
begin = generic_code.find('_')
end = begin + generic_code.count('_')
return int(max_barcode[begin:end]) + 1
@api.model
def _get_custom_barcode(self, item):
"""
if the pattern is '23.....{NNNDD}'
this function will return '23.....00000'
"""
if not item.barcode_rule_id:
return False
# Define barcode
custom_code = item.barcode_rule_id.pattern
custom_code = custom_code.replace('{', '').replace('}', '')
custom_code = custom_code.replace(
'D', self._get_replacement_char('D'))
return custom_code.replace(
'N', self._get_replacement_char('N'))
# Define barcode
custom_code = item.barcode_rule_id.pattern
custom_code = custom_code.replace('{', '').replace('}', '')
custom_code = custom_code.replace(
'D', self._get_barcode_replacement_char(
cr, uid, 'D', context=context))
custom_code = custom_code.replace(
'N', self._get_barcode_replacement_char(
cr, uid, 'N', context=context))
custom_code = custom_code.replace('.' * padding, full_base)
res[item.id] = barcode_class(custom_code)
return res
def _get_barcode_replacement_char(self, cr, uid, char, context=None):
@api.model
def _get_replacement_char(self, char):
"""
Can be overload by inheritance
Define wich character will be used instead of the 'N' or the 'D'

28
barcodes_generate/models/barcode_rule.py

@ -1,27 +1,21 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2014 GRAP (http://www.grap.coop)
# Copyright (C) 2016-Today GRAP (http://www.lalouve.net)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.osv import fields
from openerp.osv.orm import Model
from openerp import models, fields
class barcode_rule(Model):
class barcode_rule(models.Model):
_inherit = 'barcode.rule'
_columns = {
'is_product_available': fields.boolean(
string='Available for Products', help="If checked, users with"
" specific access right will have the possibility to generate"
" barcodes with this pattern for the products."),
'is_partner_available': fields.boolean(
string='Available for Partners', help="If checked, users with"
" specific access right will have the possibility to generate"
" barcodes with this pattern for the partners."),
}
is_product_available = fields.Boolean(
string='Available for Products', help="If checked, users with"
" specific access right will have the possibility to generate"
" barcodes with this pattern for the products.")
# TODO set constraint
# is_product_available and is_partner_available:
# - should be possible only for ean13 barcode rule
# - should be possible only if pattern contains at leas one '.' char
is_partner_available = fields.Boolean(
string='Available for Partners', help="If checked, users with"
" specific access right will have the possibility to generate"
" barcodes with this pattern for the partners.")

5
barcodes_generate/models/product_product.py

@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2014 GRAP (http://www.grap.coop)
# Copyright (C) 2016-Today GRAP (http://www.lalouve.net)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.osv.orm import Model
from openerp import models
class product_product(Model):
class ProductProduct(models.Model):
_name = 'product.product'
_inherit = ['product.product', 'barcode.generate.mixin']

4
barcodes_generate/models/res_partner.py

@ -3,9 +3,9 @@
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.osv.orm import Model
from openerp import models
class res_partner(Model):
class ResPartner(models.Model):
_name = 'res.partner'
_inherit = ['res.partner', 'barcode.generate.mixin']

5
barcodes_generate/security/res_groups.xml

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016-Today: GRAP (http://www.grap.coop)
Copyright (C) 2016-Today GRAP (http://www.lalouve.net)
@author Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<openerp><data>
<odoo>
<record id="generate_product_barcode" model="res.groups">
<field name="name">Generate Barcodes for Products</field>
@ -17,4 +18,4 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="category_id" ref="base.module_category_hidden" />
</record>
</data></openerp>
</odoo>

BIN
barcodes_generate/static/description/barcode_rule_form.png

After

Width: 675  |  Height: 131  |  Size: 16 KiB

0
barcodes_generate/static/description/barcode_rule.png → barcodes_generate/static/description/barcode_rule_tree.png

Before

Width: 760  |  Height: 61  |  Size: 8.8 KiB

After

Width: 760  |  Height: 61  |  Size: 8.8 KiB

BIN
barcodes_generate/static/description/product_product_form_empty.png

After

Width: 424  |  Height: 126  |  Size: 11 KiB

BIN
barcodes_generate/static/description/product_product_form_generated.png

After

Width: 334  |  Height: 80  |  Size: 8.3 KiB

5
barcodes_generate/views/view_barcode_rule.xml

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016-Today: GRAP (http://www.grap.coop)
Copyright (C) 2016-Today GRAP (http://www.lalouve.net)
@author Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<openerp><data>
<odoo>
<record id="view_barcode_rule_form" model="ir.ui.view">
<field name="model">barcode.rule</field>
@ -18,4 +19,4 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
</field>
</record>
</data></openerp>
</odoo>

25
barcodes_generate/views/view_product_product.xml

@ -1,28 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016-Today: GRAP (http://www.grap.coop)
Copyright (C) 2016-Today GRAP (http://www.lalouve.net)
@author Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<openerp><data>
<odoo>
<record id="view_product_product_form" model="ir.ui.view">
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml">
<field name="default_code" position="after">
<field name="barcode" position="before">
<field name="barcode_rule_id"
domain="[('is_product_available', '=', True)]"
groups="barcodes_generate.generate_product_barcode" colspan="2"
attrs="{'readonly': [('ean13', '!=', False)]}"/>
<field name="barcode_base" attrs="{'invisible': [('barcode_rule_id', '=', False)], 'readonly': [('ean13', '!=', False)]}"
attrs="{'readonly': [('barcode', '!=', False)]}"/>
<field name="barcode_base" attrs="{'invisible': [('barcode_rule_id', '=', False)], 'readonly': [('barcode', '!=', False)]}"
groups="barcodes_generate.generate_product_barcode" colspan="2"/>
</field>
<field name="barcode" position="after">
<button name="generate_base_barcode" type="object" string="Generate Base and Barcode"
attrs="{'invisible': ['|', '|',
('barcode_rule_id', '=', False),
('barcode', '!=', False),
('barcode_base', '!=', False)]}"
groups="barcodes_generate.generate_product_barcode" colspan="1"/>
<button name="generate_barcode" type="object" string="Generate Barcode"
attrs="{'invisible': ['|','|', ('ean13', '!=', False), ('barcode_rule_id', '=', False), ('barcode_base', '=', 0)]}"
groups="barcodes_generate.generate_product_barcode" colspan="2"/>
attrs="{'invisible': ['|',
('barcode_rule_id', '=', False),
('barcode', '!=', False)]}"
groups="barcodes_generate.generate_partner_barcode" colspan="1"/>
</field>
</field>
</record>
</data></openerp>
</odoo>

25
barcodes_generate/views/view_res_partner.xml

@ -1,28 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016-Today: GRAP (http://www.grap.coop)
Copyright (C) 2016-Today GRAP (http://www.lalouve.net)
@author Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<openerp><data>
<odoo>
<record id="view_res_partner_form" model="ir.ui.view">
<field name="model">res.partner</field>
<field name="inherit_id" ref="point_of_sale.view_partner_property_form"/>
<field name="arch" type="xml">
<field name="ean13" position="before">
<field name="barcode" position="before">
<field name="barcode_rule_id"
domain="[('is_partner_available', '=', True)]"
groups="barcodes_generate.generate_partner_barcode" colspan="2"
attrs="{'readonly': [('ean13', '!=', False)]}"/>
<field name="barcode_base" attrs="{'invisible': [('barcode_rule_id', '=', False)], 'readonly': [('ean13', '!=', False)]}"
attrs="{'readonly': [('barcode', '!=', False)]}"/>
<field name="barcode_base" attrs="{'invisible': [('barcode_rule_id', '=', False)], 'readonly': [('barcode', '!=', False)]}"
groups="barcodes_generate.generate_partner_barcode" colspan="2"/>
</field>
<field name="barcode" position="after">
<button name="generate_base_barcode" type="object" string="Generate Base and Barcode"
attrs="{'invisible': ['|', '|',
('barcode_rule_id', '=', False),
('barcode', '!=', False),
('barcode_base', '!=', False)]}"
groups="barcodes_generate.generate_partner_barcode" colspan="1"/>
<button name="generate_barcode" type="object" string="Generate Barcode"
attrs="{'invisible': ['|','|', ('ean13', '!=', False), ('barcode_rule_id', '=', False), ('barcode_base', '=', 0)]}"
groups="barcodes_generate.generate_partner_barcode" colspan="2"/>
attrs="{'invisible': ['|',
('barcode_rule_id', '=', False),
('barcode', '!=', False)]}"
groups="barcodes_generate.generate_partner_barcode" colspan="1"/>
</field>
</field>
</record>
</data></openerp>
</odoo>
Loading…
Cancel
Save