Skip to content

Commit

Permalink
[11.0][ADD] purchase_order_secondary_unit: New module to allow buy in…
Browse files Browse the repository at this point in the history
… secondary units
  • Loading branch information
sergio-teruel committed Oct 25, 2018
1 parent 412167d commit e3ccbca
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 0 deletions.
2 changes: 2 additions & 0 deletions purchase_order_secondary_unit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import models
22 changes: 22 additions & 0 deletions purchase_order_secondary_unit/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2018 Tecnativa - Sergio Teruel
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
'name': 'Purchase Order Secondary Unit',
'summary': 'Purchase product in a secondary unit',
'version': '11.0.1.0.0',
'development_status': 'Beta',
'category': 'Purchase',
'website': 'https://github.com/OCA/purchase-workflow',
'author': 'Tecnativa, Odoo Community Association (OCA)',
'license': 'AGPL-3',
'application': False,
'installable': True,
'auto_install': True,
'depends': [
'purchase',
'product_secondary_unit',
],
'data': [
'views/purchase_order_views.xml',
],
}
33 changes: 33 additions & 0 deletions purchase_order_secondary_unit/i18n/es.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_order_secondary_unit
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-25 21:04+0000\n"
"PO-Revision-Date: 2018-10-25 23:05+0200\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.0.6\n"
"Last-Translator: \n"
"Language: es\n"

#. module: purchase_order_secondary_unit
#: model:ir.model,name:purchase_order_secondary_unit.model_purchase_order_line
msgid "Purchase Order Line"
msgstr "Línea pedido de compra"

#. module: purchase_order_secondary_unit
#: model:ir.model.fields,field_description:purchase_order_secondary_unit.field_purchase_order_line_secondary_uom_qty
msgid "Secondary Qty"
msgstr "Cdad. secundaria"

#. module: purchase_order_secondary_unit
#: model:ir.model.fields,field_description:purchase_order_secondary_unit.field_purchase_order_line_secondary_uom_id
msgid "Secondary uom"
msgstr "UdM Secundaría"
2 changes: 2 additions & 0 deletions purchase_order_secondary_unit/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import purchase_order
65 changes: 65 additions & 0 deletions purchase_order_secondary_unit/models/purchase_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright 2018 Tecnativa - Sergio Teruel
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo.addons import decimal_precision as dp
from odoo.tools.float_utils import float_compare, float_round


class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'

secondary_uom_qty = fields.Float(
string='Secondary Qty',
digits=dp.get_precision('Product Unit of Measure'),
)
secondary_uom_id = fields.Many2one(
comodel_name='product.secondary.unit',
string='Secondary uom',
ondelete='restrict',
)

@api.onchange('secondary_uom_id', 'secondary_uom_qty')
def onchange_secondary_uom(self):
if not self.secondary_uom_id:
return
factor = self.secondary_uom_id.factor * self.product_uom.factor
qty = float_round(
self.secondary_uom_qty * factor,
precision_rounding=self.product_uom.rounding
)
if float_compare(
self.product_qty, qty,
precision_rounding=self.product_uom.rounding) != 0:
self.product_qty = qty

@api.onchange('product_qty')
def onchange_secondary_unit_product_qty(self):
if not self.secondary_uom_id:
return
factor = self.secondary_uom_id.factor * self.product_uom.factor
qty = float_round(
self.product_qty / (factor or 1.0),
precision_rounding=self.secondary_uom_id.uom_id.rounding
)
if float_compare(
self.secondary_uom_qty, qty,
precision_rounding=self.secondary_uom_id.uom_id.rounding) != 0:
self.secondary_uom_qty = qty

@api.onchange('product_uom')
def onchange_product_uom_for_secondary(self):
if not self.secondary_uom_id:
return
factor = self.product_uom.factor * self.secondary_uom_id.factor
qty = float_round(
self.product_qty / (factor or 1.0),
precision_rounding=self.product_uom.rounding
)
if float_compare(
self.secondary_uom_qty, qty,
precision_rounding=self.product_uom.rounding) != 0:
self.secondary_uom_qty = qty

@api.onchange('product_id')
def onchange_secondary_unit_product_id(self):
self.secondary_uom_id = self.product_id.purchase_secondary_uom_id
2 changes: 2 additions & 0 deletions purchase_order_secondary_unit/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Sergio Teruel <[email protected]>
* Sergio Teruel <[email protected]>
2 changes: 2 additions & 0 deletions purchase_order_secondary_unit/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This module extends the functionality of purchase orders to allow buy products
in secondary unit of distinct category.
7 changes: 7 additions & 0 deletions purchase_order_secondary_unit/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
To use this module you need to:

#. Go to a *Product > General Information tab*.
#. Create any record in "Secondary unit of measure".
#. Set the conversion factor.
#. Go to *Purchase > Quotation > Create*.
#. Change quantities in line and secondary unit (produc_qty will be change).
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions purchase_order_secondary_unit/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import test_purchase_order_secondary_unit
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Copyright 2018 Tecnativa - Sergio Teruel
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields
from odoo.tests import SavepointCase


class TestPurchaseOrderSecondaryUnit(SavepointCase):
at_install = False
post_install = True

@classmethod
def setUpClass(cls):
super().setUpClass()
cls.product_uom_kg = cls.env.ref('product.product_uom_kgm')
cls.product_uom_gram = cls.env.ref('product.product_uom_gram')
cls.product_uom_unit = cls.env.ref('product.product_uom_unit')
cls.product = cls.env['product.product'].create({
'name': 'test',
'uom_id': cls.product_uom_kg.id,
'uom_po_id': cls.product_uom_kg.id,
'secondary_uom_ids': [
(0, 0, {
'name': 'unit-700',
'uom_id': cls.product_uom_unit.id,
'factor': 0.7,
})],
})
cls.secondary_unit = cls.env['product.secondary.unit'].search([
('product_tmpl_id', '=', cls.product.product_tmpl_id.id),
])
cls.product.purchase_secondary_uom_id = cls.secondary_unit.id
cls.partner = cls.env['res.partner'].create({
'name': 'test - partner',
'supplier': True,
})
po = cls.env['purchase.order'].new({
'partner_id': cls.partner.id,
'company_id': cls.env.user.company_id.id,
'order_line': [(0, 0, {
'name': cls.product.name,
'product_id': cls.product.id,
'product_qty': 1,
'product_uom': cls.product.uom_id.id,
'price_unit': 1000.00,
'date_planned': fields.Datetime.now(),
})],
})
po.onchange_partner_id()
cls.order = cls.env['purchase.order'].create(
po._convert_to_write(po._cache))

def test_onchange_secondary_uom(self):
self.order.order_line.write({
'secondary_uom_id': self.secondary_unit.id,
'secondary_uom_qty': 5,
})
self.order.order_line.onchange_secondary_uom()
self.assertEqual(
self.order.order_line.product_qty, 3.5)

def test_onchange_secondary_unit_product_qty(self):
self.order.order_line.update({
'secondary_uom_id': self.secondary_unit.id,
'product_qty': 3.5,
})
self.order.order_line.onchange_secondary_unit_product_qty()
self.assertEqual(
self.order.order_line.secondary_uom_qty, 5.0)

def test_default_secondary_unit(self):
self.order.order_line.onchange_secondary_unit_product_id()
self.assertEqual(
self.order.order_line.secondary_uom_id, self.secondary_unit)

def test_onchange_order_product_uom(self):
self.order.order_line.update({
'secondary_uom_id': self.secondary_unit.id,
'product_uom': self.product_uom_gram.id,
'product_qty': 3500.00,
})
self.order.order_line.onchange_product_uom_for_secondary()
self.assertEqual(
self.order.order_line.secondary_uom_qty, 5.0)
29 changes: 29 additions & 0 deletions purchase_order_secondary_unit/views/purchase_order_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 Tecnativa - Sergio Teruel
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>

<record id="purchase_order_form" model="ir.ui.view">
<field name="name">Purchase Order Secondary Unit</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="groups_id" eval="[(4, ref('product.group_uom'))]"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='order_line']/form//field[@name='product_qty']" position="before">
<field name="secondary_uom_qty" class="oe_inline oe_no_button"
attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/>
<field name="secondary_uom_id" class="oe_inline"
attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/>
</xpath>
<xpath expr="//field[@name='order_line']/tree//field[@name='product_qty']" position="before">
<field name="secondary_uom_qty"
attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/>
<field name="secondary_uom_id"
domain="[('product_tmpl_id.product_variant_ids', 'in', [product_id])]"
options="{'no_create': True}"
attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/>
</xpath>
</field>
</record>

</odoo>

0 comments on commit e3ccbca

Please sign in to comment.