diff --git a/beesdoo_product/__init__.py b/beesdoo_product/__init__.py new file mode 100644 index 0000000..8d752fb --- /dev/null +++ b/beesdoo_product/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +import models +import wizard diff --git a/beesdoo_product/__openerp__.py b/beesdoo_product/__openerp__.py new file mode 100644 index 0000000..ac8eb60 --- /dev/null +++ b/beesdoo_product/__openerp__.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +{ + 'name': "beesdoo_product", + + 'summary': """ + Modification of product module for the needs of beescoop + - SOOO5 - Ajout de label bio/ethique/provenance""", + + 'description': """ + + """, + + 'author': "Beescoop - Cellule IT", + 'website': "https://github.com/beescoop/Obeesdoo", + + # Categories can be used to filter modules in modules listing + # Check https://github.com/odoo/odoo/blob/master/openerp/addons/base/module/module_data.xml + # for the full list + 'category': 'Sales Management', + 'version': '0.1', + + # any module necessary for this one to work correctly + 'depends': ['beesdoo_base', 'product', 'point_of_sale','pos_price_to_weight'], + + # always loaded + 'data': [ + 'data/product_label.xml', + 'data/barcode_rule.xml', + 'data/product_sequence.xml', + 'views/beesdoo_product.xml', + 'wizard/views/label_printing_utils.xml', + 'security/ir.model.access.csv', + ], + # only loaded in demonstration mode + 'demo': [], +} diff --git a/beesdoo_product/data/barcode_rule.xml b/beesdoo_product/data/barcode_rule.xml new file mode 100644 index 0000000..2c32b2a --- /dev/null +++ b/beesdoo_product/data/barcode_rule.xml @@ -0,0 +1,13 @@ + + + + + Beescoop Product Barcodes + 1 + product + 043 + 45 + ean13 + + + \ No newline at end of file diff --git a/beesdoo_product/data/product_label.xml b/beesdoo_product/data/product_label.xml new file mode 100644 index 0000000..530c946 --- /dev/null +++ b/beesdoo_product/data/product_label.xml @@ -0,0 +1,69 @@ + + + + + Label Bio ou Confiance + eco + #40ff00 + + + Agriculture raisonnée + eco + #ffa200 + + + Conventionnel + eco + #ff4000 + + + Belgique + local + #40ff00 + + + Europe + local + #ffa200 + + + Monde + local + #ff4000 + + + Label par tiers + fair + #40ff00 + + + Préserve l’intérêt + fair + #ffa200 + + + Aucune garantie + fair + #ff4000 + + + Intermédiaire coopératif + delivery + #40ff00 + + + Grossiste biologique + delivery + #ffa200 + + + Grossiste industriel + delivery + #ff4000 + + + Consignes + + + + diff --git a/beesdoo_product/data/product_sequence.xml b/beesdoo_product/data/product_sequence.xml new file mode 100644 index 0000000..f6aee05 --- /dev/null +++ b/beesdoo_product/data/product_sequence.xml @@ -0,0 +1,14 @@ + + + + + Internal reference + product.internal.code + + 5 + + 1 + + + + \ No newline at end of file diff --git a/beesdoo_product/i18n/fr_BE.po b/beesdoo_product/i18n/fr_BE.po new file mode 100644 index 0000000..9539742 --- /dev/null +++ b/beesdoo_product/i18n/fr_BE.po @@ -0,0 +1,222 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * beesdoo_product +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-13 15:12+0000\n" +"PO-Revision-Date: 2016-11-13 15:12+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: beesdoo_product +#: model:ir.ui.view,arch_db:beesdoo_product.printing_label_request_wizard +#: model:ir.ui.view,arch_db:beesdoo_product.set_label_as_printed_wizard +msgid "Cancel" +msgstr "Annuler" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_beesdoo_product_label_color_code +msgid "Color code" +msgstr "Code Couleur" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_note +msgid "Comments" +msgstr "Commentaires" + +#. module: beesdoo_product +#: model:account.tax.group,name:beesdoo_product.consignes_group_tax +msgid "Consignes" +msgstr "Consignes" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_beesdoo_product_label_create_uid +#: model:ir.model.fields,field_description:beesdoo_product.field_label_printing_wizard_create_uid +msgid "Created by" +msgstr "Créé par" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_beesdoo_product_label_create_date +#: model:ir.model.fields,field_description:beesdoo_product.field_label_printing_wizard_create_date +msgid "Created on" +msgstr "Créé le" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_default_reference_unit +msgid "Default reference unit" +msgstr "Default reference unit" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_total_deposit +msgid "Deposit Price" +msgstr "Deposit Price" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_beesdoo_product_label_display_name +#: model:ir.model.fields,field_description:beesdoo_product.field_label_printing_wizard_display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_display_unit +msgid "Display unit" +msgstr "Display unit" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_display_weight +msgid "Display weight" +msgstr "Display weight" + +#. module: beesdoo_product +#: selection:beesdoo.product.label,type:0 +msgid "Distribution" +msgstr "Distribution" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_eco_label +msgid "Eco label" +msgstr "Eco label" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_fair_label +msgid "Fair label" +msgstr "Fair label" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_beesdoo_product_label_id +#: model:ir.model.fields,field_description:beesdoo_product.field_label_printing_wizard_id +msgid "ID" +msgstr "ID" + +#. module: beesdoo_product +#: model:ir.ui.view,arch_db:beesdoo_product.beesdoo_product_form +msgid "Label" +msgstr "Label" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_label_last_printed +msgid "Label last printed on" +msgstr "Label last printed on" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_beesdoo_product_label___last_update +#: model:ir.model.fields,field_description:beesdoo_product.field_label_printing_wizard___last_update +msgid "Last Modified on" +msgstr "Dernière modification le" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_beesdoo_product_label_write_uid +#: model:ir.model.fields,field_description:beesdoo_product.field_label_printing_wizard_write_uid +msgid "Last Updated by" +msgstr "Mis à jour par" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_beesdoo_product_label_write_date +#: model:ir.model.fields,field_description:beesdoo_product.field_label_printing_wizard_write_date +msgid "Last Updated on" +msgstr "Mis à jour le" + +#. module: beesdoo_product +#: selection:beesdoo.product.label,type:0 +msgid "Local" +msgstr "Local" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_local_label +msgid "Local label" +msgstr "Local label" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_main_seller_id +msgid "Main seller id" +msgstr "Main seller id" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_beesdoo_product_label_name +msgid "Name" +msgstr "Nom" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_origin_label +msgid "Origin label" +msgstr "Origin label" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_label_to_be_printed +msgid "Print label?" +msgstr "Print label?" + +#. module: beesdoo_product +#: model:ir.model,name:beesdoo_product.model_product_template +msgid "Product Template" +msgstr "Modèle d'article" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_label_printing_wizard_product_ids +msgid "Product ids" +msgstr "Product ids" + +#. module: beesdoo_product +#: code:addons/beesdoo_product/models/beesdoo_product.py:56 +#, python-format +msgid "Reference Unit and Display Unit should belong to the same category" +msgstr "Reference Unit and Display Unit should belong to the same category" + +#. module: beesdoo_product +#: model:ir.actions.act_window,name:beesdoo_product.beesdoo_product_action_request_label_printing +#: model:ir.ui.view,arch_db:beesdoo_product.printing_label_request_wizard +msgid "Request label printing" +msgstr "Request label printing" + +#. module: beesdoo_product +#: model:ir.actions.act_window,name:beesdoo_product.beesdoo_product_action_set_label_as_printed +msgid "Set label as printed" +msgstr "Set label as printed" + +#. module: beesdoo_product +#: model:ir.ui.view,arch_db:beesdoo_product.set_label_as_printed_wizard +msgid "Set labels as printed" +msgstr "Set labels as printed" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_total_with_vat +msgid "Total Sales Price with VAT" +msgstr "Total Sales Price with VAT" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_product_template_total_with_vat_by_unit +msgid "Total Sales Price with VAT by Reference Unit" +msgstr "Total Sales Price with VAT by Reference Unit" + +#. module: beesdoo_product +#: model:ir.model.fields,field_description:beesdoo_product.field_beesdoo_product_label_type +msgid "Type" +msgstr "Type" + +#. module: beesdoo_product +#: model:ir.model,name:beesdoo_product.model_beesdoo_product_label +msgid "beesdoo.product.label" +msgstr "beesdoo.product.label" + +#. module: beesdoo_product +#: model:ir.model,name:beesdoo_product.model_label_printing_wizard +msgid "label.printing.wizard" +msgstr "label.printing.wizard" + +#. module: beesdoo_product +#: selection:beesdoo.product.label,type:0 +msgid "Écologique" +msgstr "Écologique" + +#. module: beesdoo_product +#: selection:beesdoo.product.label,type:0 +msgid "Équitable" +msgstr "Équitable" + diff --git a/beesdoo_product/models/__init__.py b/beesdoo_product/models/__init__.py new file mode 100644 index 0000000..f270af8 --- /dev/null +++ b/beesdoo_product/models/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +import beesdoo_product \ No newline at end of file diff --git a/beesdoo_product/models/beesdoo_product.py b/beesdoo_product/models/beesdoo_product.py new file mode 100644 index 0000000..d474740 --- /dev/null +++ b/beesdoo_product/models/beesdoo_product.py @@ -0,0 +1,187 @@ + # -*- coding: utf-8 -*- +from openerp import models, fields, api +from openerp.tools.translate import _ +from openerp.exceptions import UserError, ValidationError +import uuid + + +class BeesdooProduct(models.Model): + _inherit = "product.template" + + eco_label = fields.Many2one('beesdoo.product.label', domain=[('type', '=', 'eco')]) + local_label = fields.Many2one('beesdoo.product.label', domain=[('type', '=', 'local')]) + fair_label = fields.Many2one('beesdoo.product.label', domain=[('type', '=', 'fair')]) + origin_label = fields.Many2one('beesdoo.product.label', domain=[('type', '=', 'delivery')]) + + main_seller_id = fields.Many2one('res.partner', string='Main Seller', compute='_compute_main_seller_id', store=True) + + display_unit = fields.Many2one('product.uom') + default_reference_unit = fields.Many2one('product.uom') + display_weight = fields.Float(compute='_get_display_weight', store=True) + + total_with_vat = fields.Float(compute='_get_total', store=True, string="Total Sales Price with VAT") + total_with_vat_by_unit = fields.Float(compute='_get_total', store=True, string="Total Sales Price with VAT by Reference Unit") + total_deposit = fields.Float(compute='_get_total', store=True, string="Deposit Price") + + label_to_be_printed = fields.Boolean('Print label?') + label_last_printed = fields.Datetime('Label last printed on') + + note = fields.Text('Comments') + + # S0023 : List_price = Price HTVA, so add a suggested price + list_price = fields.Float(string='exVAT Price') + suggested_price = fields.Float(string='Suggested exVAT Price', compute='_compute_cost', readOnly=True) + + deadline_for_sale = fields.Integer(string="Deadline for sale(days)") + deadline_for_consumption = fields.Integer(string="Deadline for consumption(days)") + ingredients = fields.Char(string="Ingredient") + scale_label_info_1 = fields.Char(string="Scale lable info 1") + scale_label_info_2 = fields.Char(string="Scale lable info 2") + scale_sale_unit = fields.Char(compute="_get_scale_sale_uom", string="Scale sale unit", store=True) + scale_category = fields.Many2one('beesdoo.scale.category', string="Scale Category") + scale_category_code = fields.Integer(related='scale_category.code', string="Scale category code", readonly=True, store=True) + + @api.depends('uom_id','uom_id.category_id','uom_id.category_id.type') + @api.multi + def _get_scale_sale_uom(self): + for product in self: + if product.uom_id.category_id.type == 'unit': + product.scale_sale_unit = 'F' + elif product.uom_id.category_id.type == 'weight': + product.scale_sale_unit = 'P' + + def _get_main_supplier_info(self): + suppliers = self.seller_ids.sorted( + key=lambda seller: seller.date_start, + reverse=True) + if suppliers: + return suppliers[0] + else: + return suppliers + + @api.one + def generate_barcode(self): + if self.to_weight: + seq_internal_code = self.env.ref('beesdoo_product.seq_ean_product_internal_ref') + bc = '' + if not self.default_code: + rule = self.env['barcode.rule'].search([('name', '=', 'Price Barcodes (Computed Weight) 2 Decimals')])[0] + default_code = seq_internal_code.next_by_id() + while(self.search_count([('default_code', '=', default_code)]) > 1): + default_code = seq_internal_code.next_by_id() + self.default_code = default_code + ean = '02' + self.default_code[0:5] + '000000' + bc = ean[0:12] + str(self.env['barcode.nomenclature'].ean_checksum(ean)) + else: + rule = self.env['barcode.rule'].search([('name', '=', 'Beescoop Product Barcodes')])[0] + size = 13 - len(rule.pattern) + ean = rule.pattern + str(uuid.uuid4().fields[-1])[:size] + bc = ean[0:12] + str(self.env['barcode.nomenclature'].ean_checksum(ean)) + # Make sure there is no other active member with the same barcode + while(self.search_count([('barcode', '=', bc)]) > 1): + ean = rule.pattern + str(uuid.uuid4().fields[-1])[:size] + bc = ean[0:12] + str(self.env['barcode.nomenclature'].ean_checksum(ean)) + print 'barcode :', bc + self.barcode = bc + + @api.one + @api.depends('seller_ids', 'seller_ids.date_start') + def _compute_main_seller_id(self): + # Calcule le vendeur associé qui a la date de début la plus récente et plus petite qu’aujourd’hui + sellers_ids = self._get_main_supplier_info() # self.seller_ids.sorted(key=lambda seller: seller.date_start, reverse=True) + self.main_seller_id = sellers_ids and sellers_ids[0].name or False + + @api.one + @api.depends('taxes_id', 'list_price', 'taxes_id.amount', + 'taxes_id.tax_group_id', 'total_with_vat', + 'display_weight', 'weight') + def _get_total(self): + consignes_group = self.env.ref('beesdoo_product.consignes_group_tax', + raise_if_not_found=False) + + taxes_included = set(self.taxes_id.mapped('price_include')) + if len(taxes_included) == 0: + self.total_with_vat = self.list_price + return True + + elif len(taxes_included) > 1: + raise ValidationError('Several tax strategies (price_include) defined for %s' % self.name) + + elif taxes_included.pop(): + self.total_with_vat = self.list_price + self.total_deposit = sum([tax._compute_amount(self.list_price, self.list_price) for tax in self.taxes_id if tax.tax_group_id == consignes_group]) + else: + tax_amount_sum = sum([tax._compute_amount(self.list_price, self.list_price) + for tax in self.taxes_id + if tax.tax_group_id != consignes_group]) + self.total_with_vat = self.list_price + tax_amount_sum + + self.total_deposit = sum([tax._compute_amount(self.list_price, self.list_price) + for tax in self.taxes_id + if tax.tax_group_id == consignes_group]) + + if self.display_weight > 0: + self.total_with_vat_by_unit = self.total_with_vat / self.weight + + @api.one + @api.depends('weight', 'display_unit') + def _get_display_weight(self): + self.display_weight = self.weight * self.display_unit.factor + + @api.one + @api.constrains('display_unit', 'default_reference_unit') + def _unit_same_category(self): + if self.display_unit.category_id != self.default_reference_unit.category_id: + raise UserError(_('Reference Unit and Display Unit should belong to the same category')) + + @api.one + @api.depends('seller_ids') + def _compute_cost(self): + suppliers = self._get_main_supplier_info() + if(len(suppliers) > 0): + self.suggested_price = (suppliers[0].price * self.uom_po_id.factor)* (1 + suppliers[0].product_tmpl_id.categ_id.profit_margin / 100) + +class BeesdooScaleCategory(models.Model): + _name = "beesdoo.scale.category" + + name = fields.Char(string="Scale name category") + code = fields.Integer(string="Category code") + + _sql_constraints = [ + ('code_scale_categ_uniq', 'unique (code)', 'The code of the scale category must be unique !') + ] + +class BeesdooProductLabel(models.Model): + _name = "beesdoo.product.label" + + name = fields.Char() + type = fields.Selection([('eco', 'Écologique'), ('local', 'Local'), ('fair', 'Équitable'), ('delivery', 'Distribution')]) + color_code = fields.Char() + active = fields.Boolean(default=True) + +class BeesdooProductCategory(models.Model): + _inherit = "product.category" + + profit_margin = fields.Float(default = '10.0', string = "Product Margin [%]") + + @api.one + @api.constrains('profit_margin') + def _check_margin(self): + if (self.profit_margin < 0.0): + raise UserError(_('Percentages for Profit Margin must > 0.')) + +class BeesdooProductSupplierInfo(models.Model): + _inherit = "product.supplierinfo" + + price = fields.Float('exVAT Price') + +class BeesdooUOMCateg(models.Model): + _inherit = 'product.uom.categ' + + type = fields.Selection([('unit','Unit'), + ('weight','Weight'), + ('time','Time'), + ('distance','Distance'), + ('surface','Surface'), + ('volume','Volume'), + ('other','Other')],string='Category type',default='unit') diff --git a/beesdoo_product/security/ir.model.access.csv b/beesdoo_product/security/ir.model.access.csv new file mode 100644 index 0000000..1b5fb80 --- /dev/null +++ b/beesdoo_product/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +beesdoo_product_label_read_all,beesdoo.product.label Read All,model_beesdoo_product_label,,1,0,0,0 +beesdoo_product_label_all_access_sale_manager,beesdoo.product.label All Access Sale Manager,model_beesdoo_product_label,base.group_sale_manager,1,1,1,1 +beesdoo_scale_category_read_all,beesdoo.scale.category Read All,model_beesdoo_scale_category,,1,0,0,0 +beesdoo_scale_categoryl_all_access_sale_manager,beesdoo.scale.category All Access Sale Manager,model_beesdoo_scale_category,base.group_sale_manager,1,1,1,0 diff --git a/beesdoo_product/views/beesdoo_product.xml b/beesdoo_product/views/beesdoo_product.xml new file mode 100644 index 0000000..010d687 --- /dev/null +++ b/beesdoo_product/views/beesdoo_product.xml @@ -0,0 +1,188 @@ + + + + bees.product.template.form + product.template + + + +