diff --git a/pos_margin/README.rst b/pos_margin/README.rst new file mode 100644 index 00000000..b97c0917 --- /dev/null +++ b/pos_margin/README.rst @@ -0,0 +1,4 @@ +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/pos_margin/__init__.py b/pos_margin/__init__.py new file mode 100644 index 00000000..bf588bc8 --- /dev/null +++ b/pos_margin/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import report diff --git a/pos_margin/__manifest__.py b/pos_margin/__manifest__.py new file mode 100644 index 00000000..38502c1b --- /dev/null +++ b/pos_margin/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + 'name': 'PoS Order Margin', + 'summary': 'Margin on PoS Order', + 'version': '12.0.1.0.0', + 'category': 'Point Of Sale', + 'author': "GRAP," + "Odoo Community Association (OCA)", + 'website': 'https://github.com/OCA/pos', + 'license': 'AGPL-3', + 'depends': [ + 'point_of_sale', + 'sale_margin', + ], + 'data': [ + 'views/view_pos_order.xml', + ], + 'installable': True, +} diff --git a/pos_margin/i18n/es.po b/pos_margin/i18n/es.po new file mode 100644 index 00000000..b6116868 --- /dev/null +++ b/pos_margin/i18n/es.po @@ -0,0 +1,69 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_margin +# +# Translators: +# OCA Transbot , 2017 +# enjolras , 2018 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-03-01 02:01+0000\n" +"PO-Revision-Date: 2018-03-01 02:01+0000\n" +"Last-Translator: enjolras , 2018\n" +"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_line_purchase_price +msgid "Cost Price" +msgstr "Precio de coste" + +#. module: pos_margin +#: model:ir.model.fields,help:pos_margin.field_pos_order_margin +msgid "" +"It gives profitability by calculating the difference between the Unit Price " +"and the cost price." +msgstr "" +"Indica el beneficio calculando la diferencia entre el precio unitario y el " +"precio de coste." + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_pos_order_line +#, fuzzy +msgid "Lines of Point of Sale Orders" +msgstr "Líneas del punto de venta" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_line_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_margin +msgid "Margin" +msgstr "Margen" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_report_pos_order_margin_rate +#, fuzzy +msgid "Margin Rate" +msgstr "Margen" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_report_pos_order_margin_total +#, fuzzy +msgid "Margin Total" +msgstr "Margen" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_pos_order +msgid "Point of Sale Orders" +msgstr "Pedidos del TPV" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_report_pos_order +#, fuzzy +msgid "Point of Sale Orders Statistics" +msgstr "Pedidos del TPV" diff --git a/pos_margin/i18n/fr.po b/pos_margin/i18n/fr.po new file mode 100644 index 00000000..d86a037a --- /dev/null +++ b/pos_margin/i18n/fr.po @@ -0,0 +1,61 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_margin +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-08-15 11:05+0000\n" +"PO-Revision-Date: 2019-08-15 11:05+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: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_line__purchase_price +msgid "Cost Price" +msgstr "Prix de revient" + +#. module: pos_margin +#: model:ir.model.fields,help:pos_margin.field_pos_order__margin +msgid "It gives profitability by calculating the difference between the Unit Price and the cost price." +msgstr "" +"Il donne la rentabilité en calculant la différence entre le prix unitaire et " +"le prix de revient." + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order__margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_line__margin +msgid "Margin" +msgstr "Marge" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_report_pos_order__margin_rate +msgid "Margin Rate" +msgstr "Taux de marque" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_report_pos_order__margin_total +#: model_terms:ir.ui.view,arch_db:pos_margin.view_pos_order_tree +msgid "Margin Total" +msgstr "Marge Totale" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_pos_order_line +msgid "Point of Sale Order Lines" +msgstr "" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_pos_order +msgid "Point of Sale Orders" +msgstr "Commandes du point de vente" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_report_pos_order +msgid "Point of Sale Orders Report" +msgstr "" + diff --git a/pos_margin/i18n/it.po b/pos_margin/i18n/it.po new file mode 100644 index 00000000..019547b7 --- /dev/null +++ b/pos_margin/i18n/it.po @@ -0,0 +1,66 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_margin +# +# Translators: +# Francesco Fresta , 2018 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-03-01 02:01+0000\n" +"PO-Revision-Date: 2018-03-01 02:01+0000\n" +"Last-Translator: Francesco Fresta , 2018\n" +"Language-Team: Italian (https://www.transifex.com/oca/teams/23907/it/)\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_line_purchase_price +msgid "Cost Price" +msgstr "" + +#. module: pos_margin +#: model:ir.model.fields,help:pos_margin.field_pos_order_margin +msgid "" +"It gives profitability by calculating the difference between the Unit Price " +"and the cost price." +msgstr "" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_pos_order_line +#, fuzzy +msgid "Lines of Point of Sale Orders" +msgstr "Punto di riordino" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_line_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_margin +msgid "Margin" +msgstr "Margine" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_report_pos_order_margin_rate +#, fuzzy +msgid "Margin Rate" +msgstr "Margine" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_report_pos_order_margin_total +#, fuzzy +msgid "Margin Total" +msgstr "Margine" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_pos_order +msgid "Point of Sale Orders" +msgstr "Punto di riordino" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_report_pos_order +#, fuzzy +msgid "Point of Sale Orders Statistics" +msgstr "Punto di riordino" diff --git a/pos_margin/i18n/nl_NL.po b/pos_margin/i18n/nl_NL.po new file mode 100644 index 00000000..b560206c --- /dev/null +++ b/pos_margin/i18n/nl_NL.po @@ -0,0 +1,67 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_margin +# +# Translators: +# Peter Hageman , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-05-30 02:44+0000\n" +"PO-Revision-Date: 2017-05-30 02:44+0000\n" +"Last-Translator: Peter Hageman , 2017\n" +"Language-Team: Dutch (Netherlands) (https://www.transifex.com/oca/" +"teams/23907/nl_NL/)\n" +"Language: nl_NL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_line_purchase_price +msgid "Cost Price" +msgstr "Kostprijs" + +#. module: pos_margin +#: model:ir.model.fields,help:pos_margin.field_pos_order_margin +msgid "" +"It gives profitability by calculating the difference between the Unit Price " +"and the cost price." +msgstr "" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_pos_order_line +#, fuzzy +msgid "Lines of Point of Sale Orders" +msgstr "Kassaorders" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_line_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_margin +msgid "Margin" +msgstr "Marge" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_report_pos_order_margin_rate +#, fuzzy +msgid "Margin Rate" +msgstr "Marge" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_report_pos_order_margin_total +#, fuzzy +msgid "Margin Total" +msgstr "Marge" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_pos_order +msgid "Point of Sale Orders" +msgstr "Kassaorders" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_report_pos_order +#, fuzzy +msgid "Point of Sale Orders Statistics" +msgstr "Kassaorders" diff --git a/pos_margin/i18n/pos_margin.pot b/pos_margin/i18n/pos_margin.pot new file mode 100644 index 00000000..2e6bb4fa --- /dev/null +++ b/pos_margin/i18n/pos_margin.pot @@ -0,0 +1,59 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_margin +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-08-15 11:04+0000\n" +"PO-Revision-Date: 2019-08-15 11:04+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: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_line__purchase_price +msgid "Cost Price" +msgstr "" + +#. module: pos_margin +#: model:ir.model.fields,help:pos_margin.field_pos_order__margin +msgid "It gives profitability by calculating the difference between the Unit Price and the cost price." +msgstr "" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order__margin +#: model:ir.model.fields,field_description:pos_margin.field_pos_order_line__margin +msgid "Margin" +msgstr "" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_report_pos_order__margin_rate +msgid "Margin Rate" +msgstr "" + +#. module: pos_margin +#: model:ir.model.fields,field_description:pos_margin.field_report_pos_order__margin_total +#: model_terms:ir.ui.view,arch_db:pos_margin.view_pos_order_tree +msgid "Margin Total" +msgstr "" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_pos_order_line +msgid "Point of Sale Order Lines" +msgstr "" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_pos_order +msgid "Point of Sale Orders" +msgstr "" + +#. module: pos_margin +#: model:ir.model,name:pos_margin.model_report_pos_order +msgid "Point of Sale Orders Report" +msgstr "" + diff --git a/pos_margin/models/__init__.py b/pos_margin/models/__init__.py new file mode 100644 index 00000000..64f952d5 --- /dev/null +++ b/pos_margin/models/__init__.py @@ -0,0 +1,2 @@ +from . import pos_order +from . import pos_order_line diff --git a/pos_margin/models/pos_order.py b/pos_margin/models/pos_order.py new file mode 100644 index 00000000..e3f306bc --- /dev/null +++ b/pos_margin/models/pos_order.py @@ -0,0 +1,24 @@ +# Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models +import odoo.addons.decimal_precision as dp + + +class PosOrder(models.Model): + _inherit = 'pos.order' + + # Columns Section + margin = fields.Float( + 'Margin', compute='_compute_margin', store=True, + digits=dp.get_precision('Product Price'), + help="It gives profitability by calculating the difference between" + " the Unit Price and the cost price.") + + # Compute Section + @api.multi + @api.depends('lines.margin') + def _compute_margin(self): + for order in self: + order.margin = sum(order.mapped('lines.margin')) diff --git a/pos_margin/models/pos_order_line.py b/pos_margin/models/pos_order_line.py new file mode 100644 index 00000000..9cb14f33 --- /dev/null +++ b/pos_margin/models/pos_order_line.py @@ -0,0 +1,42 @@ +# Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models +import odoo.addons.decimal_precision as dp + + +class PosOrderLine(models.Model): + _inherit = 'pos.order.line' + + # Columns Section + margin = fields.Float( + 'Margin', compute='_compute_multi_margin', store=True, + multi='multi_margin', digits=dp.get_precision('Product Price')) + + purchase_price = fields.Float( + 'Cost Price', compute='_compute_multi_margin', store=True, + multi='multi_margin', digits=dp.get_precision('Product Price')) + + # Compute Section + @api.multi + @api.depends('product_id', 'qty', 'price_subtotal') + def _compute_multi_margin(self): + for line in self.filtered('product_id'): + purchase_price = self._get_purchase_price(line) + line.purchase_price = purchase_price + line.margin = line.price_subtotal - (purchase_price * line.qty) + + @api.model + def _get_purchase_price(self, line): + # We call _get_purchase_price from sale_margin module, to reuse + # computation that handles multi currencies context and UoM + SaleOrderLine = self.env['sale.order.line'] + + # if used in combination with module which does add the uom_id to line + uom = hasattr(line, 'uom_id') and line.uom_id\ + or line.product_id.uom_id + + return SaleOrderLine._get_purchase_price( + line.order_id.pricelist_id, line.product_id, uom, + line.order_id.date_order)['purchase_price'] diff --git a/pos_margin/readme/CONTRIBUTORS.rst b/pos_margin/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..3b5f0996 --- /dev/null +++ b/pos_margin/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Sylvain LE GAL (https://twitter.com/legalsylvain) +* Wolfgang Pichler diff --git a/pos_margin/readme/DESCRIPTION.rst b/pos_margin/readme/DESCRIPTION.rst new file mode 100644 index 00000000..48bcde4b --- /dev/null +++ b/pos_margin/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +This module extends the functionality of point of sale to support margin on +pos orders. + +This gives the profitability by calculating the difference between the Unit +Price and Cost Price. diff --git a/pos_margin/readme/HISTORY.rst b/pos_margin/readme/HISTORY.rst new file mode 100644 index 00000000..04bbd269 --- /dev/null +++ b/pos_margin/readme/HISTORY.rst @@ -0,0 +1,8 @@ +12.0.1.0.0 +~~~~~~~~~~ + +* Migrate to V12.0 +* Reuse ``sale_margin`` computation to handle multi currency context. +* Correct computation of margin, if a module that adds ``uom_id`` on + ``pos.order.line`` is installed. +* Add test diff --git a/pos_margin/readme/ROADMAP.rst b/pos_margin/readme/ROADMAP.rst new file mode 100644 index 00000000..c01e849e --- /dev/null +++ b/pos_margin/readme/ROADMAP.rst @@ -0,0 +1,7 @@ +This module depends on ``sale_margin`` module to reuse algorithm present in the +function ``_get_purchase_price`` of the model ``sale.order.line`` to +compute correctly purchase price, in a multicurrency context. + +This dependency can be removed, when Odoo Core will be correctly refactored, +moving this ``@api.model`` function in a more generic module (``account`` +for exemple). diff --git a/pos_margin/readme/USAGE.rst b/pos_margin/readme/USAGE.rst new file mode 100644 index 00000000..e719a37a --- /dev/null +++ b/pos_margin/readme/USAGE.rst @@ -0,0 +1,7 @@ +To use this module, you need to: + +* Go to 'Point Of Sale' / 'Orders' / 'Orders' +* Open an order + +.. figure:: ../static/description/pos_order_form.png + :width: 800px diff --git a/pos_margin/report/__init__.py b/pos_margin/report/__init__.py new file mode 100644 index 00000000..225fc1d2 --- /dev/null +++ b/pos_margin/report/__init__.py @@ -0,0 +1,2 @@ +from . import pos_order_report + diff --git a/pos_margin/report/pos_order_report.py b/pos_margin/report/pos_order_report.py new file mode 100644 index 00000000..ae826b40 --- /dev/null +++ b/pos_margin/report/pos_order_report.py @@ -0,0 +1,15 @@ +from odoo import fields, models + + +class PosOrderReport(models.Model): + _inherit = 'report.pos.order' + + margin_total = fields.Float(string='Margin Total') + margin_rate = fields.Float(string='Margin Rate', group_operator='avg') + + def _select(self): + return super(PosOrderReport, self)._select() + """, + SUM(l.margin) as margin_total, + (SUM(l.margin / nullif(l.qty,0)) * 100 / + SUM(nullif(l.purchase_price,0)))::decimal as margin_rate + """ diff --git a/pos_margin/static/description/icon.png b/pos_margin/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/pos_margin/static/description/icon.png differ diff --git a/pos_margin/static/description/pos_order_form.png b/pos_margin/static/description/pos_order_form.png new file mode 100644 index 00000000..22601768 Binary files /dev/null and b/pos_margin/static/description/pos_order_form.png differ diff --git a/pos_margin/tests/__init__.py b/pos_margin/tests/__init__.py new file mode 100644 index 00000000..d9b96c4f --- /dev/null +++ b/pos_margin/tests/__init__.py @@ -0,0 +1 @@ +from . import test_module diff --git a/pos_margin/tests/test_module.py b/pos_margin/tests/test_module.py new file mode 100644 index 00000000..174a2681 --- /dev/null +++ b/pos_margin/tests/test_module.py @@ -0,0 +1,68 @@ +# Copyright 2019 - Today Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields +from odoo.tests.common import TransactionCase + + +class TestModule(TransactionCase): + + def setUp(self): + super(TestModule, self).setUp() + self.PosOrder = self.env['pos.order'] + self.pos_product = self.env.ref('point_of_sale.whiteboard_pen') + self.pricelist = self.env.ref('product.list0') + + # Create a new pos config and open it + self.pos_config = self.env.ref('point_of_sale.pos_config_main').copy() + self.pos_config.open_session_cb() + + def test_margin(self): + self.pos_product.list_price = 1.8 + self.pos_product.standard_price = 0.5 + order = self._create_order() + + self.assertEqual( + order.margin, 10 * (1.8 - 0.5), + "Bad computation of margin") + + def _create_order(self): + # Create order + order_data = { + 'id': u'0006-001-0010', + 'to_invoice': False, + 'data': { + 'pricelist_id': self.pricelist.id, + 'user_id': 1, + 'name': 'Order 0006-001-0010', + 'partner_id': False, + 'amount_paid': 0.9, + 'pos_session_id': self.pos_config.current_session_id.id, + 'lines': [[0, 0, { + 'product_id': self.pos_product.id, + 'price_unit': self.pos_product.list_price, + 'qty': 10, + 'price_subtotal': 18.0, + 'price_subtotal_incl': 18.0, + }]], + 'statement_ids': [[0, 0, { + 'journal_id': self.pos_config.journal_ids[0].id, + 'amount': 18.0, + 'name': fields.Datetime.now(), + 'account_id': + self.env.user.partner_id.property_account_receivable_id.id, + 'statement_id': + self.pos_config.current_session_id.statement_ids[0].id, + }]], + 'creation_date': u'2018-09-27 15:51:03', + 'amount_tax': 0, + 'fiscal_position_id': False, + 'uid': u'00001-001-0001', + 'amount_return': 0, + 'sequence_number': 1, + 'amount_total': 18.0, + }} + + result = self.PosOrder.create_from_ui([order_data]) + order = self.PosOrder.browse(result[0]) + return order diff --git a/pos_margin/views/view_pos_order.xml b/pos_margin/views/view_pos_order.xml new file mode 100644 index 00000000..75d24452 --- /dev/null +++ b/pos_margin/views/view_pos_order.xml @@ -0,0 +1,33 @@ + + + + + + + pos.order + + + + + + + + + + + + + pos.order + + + + + + + + +