From 82f2ce4fbd39e3bbf3ef753d5fdea468bb477a31 Mon Sep 17 00:00:00 2001
From: Sudhir Arya
Date: Thu, 31 Dec 2015 19:24:48 +0530
Subject: [PATCH 01/56] Added Purchase Operating Unit module.
---
purchase_operating_unit/README.rst | 64 +++++++++++++
purchase_operating_unit/__init__.py | 5 +
purchase_operating_unit/__openerp__.py | 27 ++++++
.../demo/purchase_order_demo.xml | 34 +++++++
purchase_operating_unit/models/__init__.py | 8 ++
purchase_operating_unit/models/invoice.py | 21 +++++
purchase_operating_unit/models/procurement.py | 34 +++++++
purchase_operating_unit/models/purchase.py | 75 +++++++++++++++
.../security/purchase_security.xml | 28 ++++++
.../static/description/icon.png | Bin 0 -> 9455 bytes
purchase_operating_unit/tests/__init__.py | 7 ++
.../tests/test_po_security.py | 43 +++++++++
.../tests/test_purchase_operating_unit.py | 89 ++++++++++++++++++
.../views/purchase_order_line_view.xml | 43 +++++++++
.../views/purchase_order_view.xml | 52 ++++++++++
15 files changed, 530 insertions(+)
create mode 100644 purchase_operating_unit/README.rst
create mode 100644 purchase_operating_unit/__init__.py
create mode 100644 purchase_operating_unit/__openerp__.py
create mode 100644 purchase_operating_unit/demo/purchase_order_demo.xml
create mode 100644 purchase_operating_unit/models/__init__.py
create mode 100644 purchase_operating_unit/models/invoice.py
create mode 100644 purchase_operating_unit/models/procurement.py
create mode 100644 purchase_operating_unit/models/purchase.py
create mode 100644 purchase_operating_unit/security/purchase_security.xml
create mode 100644 purchase_operating_unit/static/description/icon.png
create mode 100644 purchase_operating_unit/tests/__init__.py
create mode 100644 purchase_operating_unit/tests/test_po_security.py
create mode 100644 purchase_operating_unit/tests/test_purchase_operating_unit.py
create mode 100644 purchase_operating_unit/views/purchase_order_line_view.xml
create mode 100644 purchase_operating_unit/views/purchase_order_view.xml
diff --git a/purchase_operating_unit/README.rst b/purchase_operating_unit/README.rst
new file mode 100644
index 0000000000..b034157cff
--- /dev/null
+++ b/purchase_operating_unit/README.rst
@@ -0,0 +1,64 @@
+.. image:: https://img.shields.io/badge/license-AGPLv3-blue.svg
+ :target: https://www.gnu.org/licenses/lgpl.html
+ :alt: License: LGPL-3
+
+===============================
+Purchase with Operating Units
+===============================
+
+This module introduces the following features:
+- It introduces the operating unit to the purchase order.
+- The operating unit is copied to the invoice.
+- The operating unit is copied to the stock picking.
+- It implements user's security rules.
+
+
+Configuration
+=============
+
+
+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/213/7.0
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub 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 `_.
+
+Contributors
+------------
+
+* Jordi Ballester Alomar
+* Aaron Henriquez
+* Sudhir Arya
+
+Maintainer
+----------
+
+.. image:: https://odoo-community.org/logo.png
+ :alt: Odoo Community Association
+ :target: http://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 http://odoo-community.org.
diff --git a/purchase_operating_unit/__init__.py b/purchase_operating_unit/__init__.py
new file mode 100644
index 0000000000..cf1a072540
--- /dev/null
+++ b/purchase_operating_unit/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# © 2016 Eficent Business and IT Consulting Services S.L.
+# © 2016 Serpent Consulting Services Pvt. Ltd.
+# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
+from . import models
diff --git a/purchase_operating_unit/__openerp__.py b/purchase_operating_unit/__openerp__.py
new file mode 100644
index 0000000000..980fd08585
--- /dev/null
+++ b/purchase_operating_unit/__openerp__.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# © 2015 Eficent Business and IT Consulting Services S.L.
+# - Jordi Ballester Alomar
+# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
+
+{
+ "name": "Operating Unit in Purchase Orders",
+ "summary": "An operating unit (OU) is an organizational entity part of a\
+ company",
+ "version": "9.0.1.0.0",
+ "author": "Eficent, Serpent Consulting Services Pvt. Ltd.,"
+ "Odoo Community Association (OCA)",
+ "website": "http://www.eficent.com",
+ "category": "Purchase Management",
+ "depends": ["purchase", "procurement_operating_unit"],
+ "license": "LGPL-3",
+ "data": [
+ "security/purchase_security.xml",
+ "views/purchase_order_view.xml",
+ "views/purchase_order_line_view.xml",
+ ],
+ "demo": [
+ "demo/purchase_order_demo.xml",
+ ],
+ "installable": True,
+}
diff --git a/purchase_operating_unit/demo/purchase_order_demo.xml b/purchase_operating_unit/demo/purchase_order_demo.xml
new file mode 100644
index 0000000000..fc427bfe36
--- /dev/null
+++ b/purchase_operating_unit/demo/purchase_order_demo.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/purchase_operating_unit/models/__init__.py b/purchase_operating_unit/models/__init__.py
new file mode 100644
index 0000000000..eeebb4267f
--- /dev/null
+++ b/purchase_operating_unit/models/__init__.py
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+# © 2015 Eficent Business and IT Consulting Services S.L.
+# - Jordi Ballester Alomar
+# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
+from . import purchase
+from . import procurement
+from . import invoice
diff --git a/purchase_operating_unit/models/invoice.py b/purchase_operating_unit/models/invoice.py
new file mode 100644
index 0000000000..eff0a4266c
--- /dev/null
+++ b/purchase_operating_unit/models/invoice.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# © 2015 Eficent Business and IT Consulting Services S.L.
+# - Jordi Ballester Alomar
+# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
+from openerp import api, models
+
+
+class AccountInvoice(models.Model):
+ _inherit = 'account.invoice'
+
+ # Load all unsold PO lines
+ @api.onchange('purchase_id')
+ def purchase_order_change(self):
+ """
+ Override to add Operating Unit from Purchase Order to Invoice.
+ """
+ if self.purchase_id and self.purchase_id.operating_unit_id:
+ # Assign OU from PO to Invoice
+ self.operating_unit_id = self.purchase_id.operating_unit_id.id
+ return super(AccountInvoice, self).purchase_order_change()
diff --git a/purchase_operating_unit/models/procurement.py b/purchase_operating_unit/models/procurement.py
new file mode 100644
index 0000000000..709a529e53
--- /dev/null
+++ b/purchase_operating_unit/models/procurement.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# © 2015 Eficent Business and IT Consulting Services S.L.
+# - Jordi Ballester Alomar
+# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
+from openerp import api, models
+from openerp.tools.translate import _
+from openerp.exceptions import UserError
+
+
+class ProcurementOrder(models.Model):
+ _inherit = 'procurement.order'
+
+ @api.one
+ @api.constrains('operating_unit_id', 'purchase_line_id')
+ def _check_purchase_order_operating_unit(self, cr, uid, ids, context=None):
+ purchase = self.purchase_line_id.purchase_id
+ if purchase and\
+ self.purchase.operating_unit_id !=\
+ self.location_id.operating_unit_id:
+ raise UserError(_('Configuration error!\nThe Quotation / Purchase\
+ Order and the Procurement Order must belong to the\
+ same Operating Unit.'))
+
+ @api.multi
+ def _prepare_purchase_order(self, partner):
+ res = super(ProcurementOrder, self)._prepare_purchase_order(partner)
+ operating_unit = self.location_id.operating_unit_id
+ if operating_unit:
+ res.update({
+ 'operating_unit_id': operating_unit.id,
+ 'requesting_operating_unit_id': operating_unit.id
+ })
+ return res
diff --git a/purchase_operating_unit/models/purchase.py b/purchase_operating_unit/models/purchase.py
new file mode 100644
index 0000000000..65562264ff
--- /dev/null
+++ b/purchase_operating_unit/models/purchase.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+# © 2015 Eficent Business and IT Consulting Services S.L.
+# - Jordi Ballester Alomar
+# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
+from openerp.tools.translate import _
+from openerp import api, fields, models
+from openerp.exceptions import UserError
+
+
+class PurchaseOrder(models.Model):
+ _inherit = 'purchase.order'
+
+ operating_unit_id = fields.Many2one('operating.unit', 'Operating Unit',
+ default=lambda self:
+ self.env['res.users'].
+ operating_unit_default_get(self._uid))
+ requesting_operating_unit_id =\
+ fields.Many2one('operating.unit', 'Requesting Operating Unit',
+ default=lambda self:
+ self.env['res.users'].
+ operating_unit_default_get(self._uid))
+
+# @api.one
+# @api.constrains('operating_unit_id', 'picking_type_id')
+# def _check_warehouse_operating_unit(self):
+# picking_type = self.picking_type_id
+# if picking_type:
+# if picking_type.warehouse_id and\
+# picking_type.warehouse_id.operating_unit_id\
+# and self.operating_unit_id and\
+# picking_type.warehouse_id.operating_unit_id !=\
+# self.operating_unit_id:
+# raise UserError(_('Configuration error!\nThe\
+# Quotation / Purchase Order and the Warehouse of picking type\
+# must belong to the same Operating Unit.'))
+
+ @api.one
+ @api.constrains('operating_unit_id', 'requesting_operating_unit_id',
+ 'company_id')
+ def _check_company_operating_unit(self):
+ if self.company_id and self.operating_unit_id and\
+ self.company_id != self.operating_unit_id.company_id:
+ raise UserError(_('Configuration error!\nThe Company in the\
+ Purchase Order and in the Operating Unit must be the same.'))
+
+ @api.onchange('requesting_operating_unit_id', 'operating_unit_id')
+ def onchange_operating_unit_id(self):
+ pick_type = self.env['stock.picking.type']
+ location_obj = self.env['stock.location']
+ if not self.requesting_operating_unit_id or not self.operating_unit_id:
+ return {}
+ request_locations =\
+ location_obj.search([('operating_unit_id', '=',
+ self.requesting_operating_unit_id.id)])
+ picking_types =\
+ pick_type.search([('default_location_dest_id', 'in',
+ request_locations.ids)], limit=1)
+ if picking_types:
+ self.picking_type_id = picking_types.id
+
+ @api.model
+ def _prepare_picking(self):
+ res = super(PurchaseOrder, self)._prepare_picking()
+ res['operating_unit_id'] = self.operating_unit_id and\
+ self.operating_unit_id.id
+ return res
+
+
+class PurchaseOrderLine(models.Model):
+ _inherit = 'purchase.order.line'
+
+ operating_unit_id = fields.Many2one('operating.unit',
+ related='order_id.operating_unit_id',
+ string='Operating Unit', readonly=True)
diff --git a/purchase_operating_unit/security/purchase_security.xml b/purchase_operating_unit/security/purchase_security.xml
new file mode 100644
index 0000000000..14cdd36be4
--- /dev/null
+++ b/purchase_operating_unit/security/purchase_security.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+ ['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]
+ PO's from allowed operating units
+
+
+
+
+
+
+
+
+
+ ['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]
+ PO lines from allowed operating units
+
+
+
+
+
+
+
+
+
diff --git a/purchase_operating_unit/static/description/icon.png b/purchase_operating_unit/static/description/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d
GIT binary patch
literal 9455
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
z
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
Xviia!U7SGha1wx#SCgwmn*{w2TRX*I
literal 0
HcmV?d00001
diff --git a/purchase_operating_unit/tests/__init__.py b/purchase_operating_unit/tests/__init__.py
new file mode 100644
index 0000000000..cb1343a28e
--- /dev/null
+++ b/purchase_operating_unit/tests/__init__.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+# © 2015 Eficent Business and IT Consulting Services S.L.
+# - Jordi Ballester Alomar
+# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
+from . import test_purchase_operating_unit
+from . import test_po_security
diff --git a/purchase_operating_unit/tests/test_po_security.py b/purchase_operating_unit/tests/test_po_security.py
new file mode 100644
index 0000000000..104acaa1bf
--- /dev/null
+++ b/purchase_operating_unit/tests/test_po_security.py
@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+# © 2015 Eficent Business and IT Consulting Services S.L.
+# - Jordi Ballester Alomar
+# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
+from openerp.addons.purchase_operating_unit.tests import\
+ test_purchase_order as test_po
+
+
+class TestPoSecurity(test_po.TestPurchaseOrder):
+
+ def test_po_ou_security(self):
+ """Test Security of Purchase Operating Unit"""
+ # User 2 is only assigned to Operating Unit 2, and cannot list
+ # purchase orders from Operating Unit 1.
+ po_ids =\
+ self.PurchaseOrder.sudo(self.user2_id).\
+ search([('operating_unit_id', '=', self.ou1.id)]).ids
+ self.assertEqual(po_ids, [])
+ # User 2 cannot list the picking that was created from PO 1
+ picking_ids =\
+ self.StockPikcing.sudo(self.user2_id).\
+ search([('id', 'in', self.purchase1.picking_ids.ids)]).ids
+ self.assertEqual(picking_ids, [])
+ # User 2 cannot list the invoice that was created from PO 2
+ invoice_ids = self.AccountInvoice.sudo(self.user2_id).\
+ search([('purchase_id', '=', self.purchase1.id)]).ids
+ self.assertEqual(invoice_ids, [])
+ # User 1 is assigned to Operating Unit 1, and can list
+ # the purchase order 1 from Operating Unit 1.
+ po_ids =\
+ self.PurchaseOrder.sudo(self.user1_id).\
+ search([('operating_unit_id', '=', self.ou1.id)]).ids
+ self.assertNotEqual(po_ids, [])
+ # User 1 can list the picking that was created from PO 1
+ picking_ids =\
+ self.StockPikcing.sudo(self.user1_id).\
+ search([('id', 'in', self.purchase1.picking_ids.ids)]).ids
+ self.assertNotEqual(picking_ids, [])
+ # User 1 can list the invoice that was created from PO 2
+ invoice_ids = self.AccountInvoice.sudo(self.user1_id).\
+ search([('purchase_id', '=', self.purchase1.id)]).ids
+ self.assertNotEqual(invoice_ids, [])
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
new file mode 100644
index 0000000000..d992ad0204
--- /dev/null
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+# © 2015 Eficent Business and IT Consulting Services S.L.
+# - Jordi Ballester Alomar
+# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
+import time
+from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
+from openerp.addons.purchase.tests import test_purchase_order
+
+
+class TestPurchaseOperatingUnit(test_purchase_order.TestPurchaseOrder):
+
+ def setUp(self):
+ super(TestPurchaseOperatingUnit, self).setUp()
+ self.ResUsers = self.env['res.users']
+ self.StockMove = self.env['stock.move']
+ self.StockPikcing = self.env['stock.picking']
+ # company
+ self.company1 = self.env.ref('base.main_company')
+ self.company2 = self.env.ref('stock.res_company_1')
+ # groups
+ self.group_purchase_user = self.env.ref('purchase.group_purchase_user')
+ self.group_stock_user = self.env.ref('stock.group_stock_user')
+ # Main Operating Unit
+ self.ou1 = self.env.ref('operating_unit.main_operating_unit')
+ # B2B Operating Unit
+ self.b2b = self.env.ref('operating_unit.b2b_operating_unit')
+ # Partner
+ self.partner1 = self.env.ref('base.res_partner_1')
+ # Products
+ self.product1 = self.env.ref('product.product_product_7')
+ self.product2 = self.env.ref('product.product_product_9')
+ self.product3 = self.env.ref('product.product_product_11')
+ # Create users
+ self.user1_id = self._create_user('user_1',
+ [self.group_purchase_user,
+ self.group_stock_user],
+ self.company1,
+ [self.ou1])
+ self.user2_id = self._create_user('user_2',
+ [self.group_purchase_user,
+ self.group_stock_user],
+ self.company2,
+ [self.b2b])
+ self.purchase1 = self._create_purchase(
+ self.user1_id, [(self.product1, 1000),
+ (self.product2, 500),
+ (self.product3, 800)])
+ self.purchase1.sudo(self.user1_id).button_confirm()
+
+ def _create_user(self, login, groups, company, operating_units):
+ """ Create a user."""
+ group_ids = [group.id for group in groups]
+ user =\
+ self.ResUsers.with_context({'no_reset_password': True}).\
+ create({
+ 'name': 'Chicago Purchase User',
+ 'login': login,
+ 'password': 'demo',
+ 'email': 'chicago@yourcompany.com',
+ 'company_id': company.id,
+ 'company_ids': [(4, company.id)],
+ 'operating_unit_ids': [(4, ou.id) for ou in operating_units],
+ 'groups_id': [(6, 0, group_ids)]
+ })
+ return user.id
+
+ def _create_purchase(self, user_id, line_products):
+ """ Create a purchase order.
+ ``line_products`` is a list of tuple [(product, qty)]
+ """
+ lines = []
+ for product, qty in line_products:
+ line_values = {
+ 'name': product.name,
+ 'product_id': product.id,
+ 'product_qty': qty,
+ 'product_uom': product.uom_id.id,
+ 'price_unit': 50,
+ 'date_planned': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
+ }
+ lines.append((0, 0, line_values))
+ return self.PurchaseOrder.sudo(user_id).create({
+ 'operating_unit_id': self.ou1.id,
+ 'requesting_operating_unit_id': self.ou1.id,
+ 'partner_id': self.partner1.id,
+ 'order_line': lines,
+ 'company_id': self.company1.id,
+ })
diff --git a/purchase_operating_unit/views/purchase_order_line_view.xml b/purchase_operating_unit/views/purchase_order_line_view.xml
new file mode 100644
index 0000000000..283a8d9bc5
--- /dev/null
+++ b/purchase_operating_unit/views/purchase_order_line_view.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+ purchase_order_line_tree
+ purchase.order.line
+
+
+
+
+
+
+
+
+
+ purchase_order_line_form
+ purchase.order.line
+
+
+
+
+
+
+
+
+
+ purchase_order_line_search
+ purchase.order.line
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/purchase_operating_unit/views/purchase_order_view.xml b/purchase_operating_unit/views/purchase_order_view.xml
new file mode 100644
index 0000000000..cb3d7d9e4b
--- /dev/null
+++ b/purchase_operating_unit/views/purchase_order_view.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+ purchase_order_tree
+ purchase.order
+
+
+
+
+
+
+
+
+
+ purchase_order_form
+ purchase.order
+
+
+
+
+
+
+
+
+
+ {'operating_unit_id': operating_unit_id}
+
+
+
+
+
+
+
+
+ view_purchase_order_filter
+ purchase.order
+
+
+
+
+
+
+
+
+
+
+
+
+
From d53de72f70303a9ac506e14faed69861c65f94fc Mon Sep 17 00:00:00 2001
From: Sudhir Arya
Date: Sat, 2 Jan 2016 15:10:14 +0530
Subject: [PATCH 02/56] Improved the unit test case for Purchase OU.
---
purchase_operating_unit/tests/test_po_security.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/purchase_operating_unit/tests/test_po_security.py b/purchase_operating_unit/tests/test_po_security.py
index 104acaa1bf..b1449e711c 100644
--- a/purchase_operating_unit/tests/test_po_security.py
+++ b/purchase_operating_unit/tests/test_po_security.py
@@ -4,10 +4,10 @@
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from openerp.addons.purchase_operating_unit.tests import\
- test_purchase_order as test_po
+ test_purchase_operating_unit as test_po_ou
-class TestPoSecurity(test_po.TestPurchaseOrder):
+class TestPoSecurity(test_po_ou.TestPurchaseOperatingUnit):
def test_po_ou_security(self):
"""Test Security of Purchase Operating Unit"""
From df79c4fa69907b45630da9092cc69c74bccadc9c Mon Sep 17 00:00:00 2001
From: Sudhir Arya
Date: Fri, 8 Jan 2016 11:19:47 +0530
Subject: [PATCH 03/56] Improved the code of unit test cases and of constraint.
---
purchase_operating_unit/models/procurement.py | 2 +-
purchase_operating_unit/tests/test_po_security.py | 4 ++--
purchase_operating_unit/tests/test_purchase_operating_unit.py | 3 +--
3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/purchase_operating_unit/models/procurement.py b/purchase_operating_unit/models/procurement.py
index 709a529e53..7cd036d19e 100644
--- a/purchase_operating_unit/models/procurement.py
+++ b/purchase_operating_unit/models/procurement.py
@@ -12,7 +12,7 @@ class ProcurementOrder(models.Model):
_inherit = 'procurement.order'
@api.one
- @api.constrains('operating_unit_id', 'purchase_line_id')
+ @api.constrains('purchase_line_id')
def _check_purchase_order_operating_unit(self, cr, uid, ids, context=None):
purchase = self.purchase_line_id.purchase_id
if purchase and\
diff --git a/purchase_operating_unit/tests/test_po_security.py b/purchase_operating_unit/tests/test_po_security.py
index b1449e711c..293f7b2b8c 100644
--- a/purchase_operating_unit/tests/test_po_security.py
+++ b/purchase_operating_unit/tests/test_po_security.py
@@ -19,7 +19,7 @@ def test_po_ou_security(self):
self.assertEqual(po_ids, [])
# User 2 cannot list the picking that was created from PO 1
picking_ids =\
- self.StockPikcing.sudo(self.user2_id).\
+ self.StockPicking.sudo(self.user2_id).\
search([('id', 'in', self.purchase1.picking_ids.ids)]).ids
self.assertEqual(picking_ids, [])
# User 2 cannot list the invoice that was created from PO 2
@@ -34,7 +34,7 @@ def test_po_ou_security(self):
self.assertNotEqual(po_ids, [])
# User 1 can list the picking that was created from PO 1
picking_ids =\
- self.StockPikcing.sudo(self.user1_id).\
+ self.StockPicking.sudo(self.user1_id).\
search([('id', 'in', self.purchase1.picking_ids.ids)]).ids
self.assertNotEqual(picking_ids, [])
# User 1 can list the invoice that was created from PO 2
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
index d992ad0204..b352e5d863 100644
--- a/purchase_operating_unit/tests/test_purchase_operating_unit.py
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -13,8 +13,7 @@ class TestPurchaseOperatingUnit(test_purchase_order.TestPurchaseOrder):
def setUp(self):
super(TestPurchaseOperatingUnit, self).setUp()
self.ResUsers = self.env['res.users']
- self.StockMove = self.env['stock.move']
- self.StockPikcing = self.env['stock.picking']
+ self.StockPicking = self.env['stock.picking']
# company
self.company1 = self.env.ref('base.main_company')
self.company2 = self.env.ref('stock.res_company_1')
From 989e62adf38a2d89f5e96dac53888bd9ce5cd967 Mon Sep 17 00:00:00 2001
From: Sudhir Arya
Date: Mon, 22 Feb 2016 15:47:06 +0530
Subject: [PATCH 04/56] Migrated the module with test cases.
---
purchase_operating_unit/README.rst | 2 +-
purchase_operating_unit/__openerp__.py | 3 +-
purchase_operating_unit/models/procurement.py | 6 +-
purchase_operating_unit/models/purchase.py | 111 ++++++++++++------
.../tests/test_po_security.py | 4 +-
.../tests/test_purchase_operating_unit.py | 23 +++-
6 files changed, 107 insertions(+), 42 deletions(-)
diff --git a/purchase_operating_unit/README.rst b/purchase_operating_unit/README.rst
index b034157cff..a738cb85da 100644
--- a/purchase_operating_unit/README.rst
+++ b/purchase_operating_unit/README.rst
@@ -22,7 +22,7 @@ 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/213/7.0
+ :target: https://runbot.odoo-community.org/runbot/213/9.0
Bug Tracker
===========
diff --git a/purchase_operating_unit/__openerp__.py b/purchase_operating_unit/__openerp__.py
index 980fd08585..3384aaf801 100644
--- a/purchase_operating_unit/__openerp__.py
+++ b/purchase_operating_unit/__openerp__.py
@@ -9,7 +9,8 @@
"summary": "An operating unit (OU) is an organizational entity part of a\
company",
"version": "9.0.1.0.0",
- "author": "Eficent, Serpent Consulting Services Pvt. Ltd.,"
+ "author": "Eficent Business and IT Consulting Services S.L., "
+ "Serpent Consulting Services Pvt. Ltd.,"
"Odoo Community Association (OCA)",
"website": "http://www.eficent.com",
"category": "Purchase Management",
diff --git a/purchase_operating_unit/models/procurement.py b/purchase_operating_unit/models/procurement.py
index 7cd036d19e..bd98de86bc 100644
--- a/purchase_operating_unit/models/procurement.py
+++ b/purchase_operating_unit/models/procurement.py
@@ -13,10 +13,10 @@ class ProcurementOrder(models.Model):
@api.one
@api.constrains('purchase_line_id')
- def _check_purchase_order_operating_unit(self, cr, uid, ids, context=None):
+ def _check_purchase_order_operating_unit(self):
purchase = self.purchase_line_id.purchase_id
- if purchase and\
- self.purchase.operating_unit_id !=\
+ if purchase and \
+ purchase.operating_unit_id !=\
self.location_id.operating_unit_id:
raise UserError(_('Configuration error!\nThe Quotation / Purchase\
Order and the Procurement Order must belong to the\
diff --git a/purchase_operating_unit/models/purchase.py b/purchase_operating_unit/models/purchase.py
index 65562264ff..9d142b31b9 100644
--- a/purchase_operating_unit/models/purchase.py
+++ b/purchase_operating_unit/models/purchase.py
@@ -3,14 +3,26 @@
# - Jordi Ballester Alomar
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-from openerp.tools.translate import _
-from openerp import api, fields, models
-from openerp.exceptions import UserError
+from openerp import _, api, exceptions, fields, models
+from openerp.exceptions import Warning
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
+ @api.model
+ def _default_picking_type(self):
+ res = super(PurchaseOrder, self)._default_picking_type()
+ type_obj = self.env['stock.picking.type']
+ operating_unit = self.env['res.users'].operating_unit_default_get(
+ self._uid)
+ types = type_obj.search([('code', '=', 'incoming'),
+ ('warehouse_id.operating_unit_id', '=',
+ operating_unit.id)])
+ if types:
+ res = types[:1].id
+ return res
+
operating_unit_id = fields.Many2one('operating.unit', 'Operating Unit',
default=lambda self:
self.env['res.users'].
@@ -21,19 +33,29 @@ class PurchaseOrder(models.Model):
self.env['res.users'].
operating_unit_default_get(self._uid))
-# @api.one
-# @api.constrains('operating_unit_id', 'picking_type_id')
-# def _check_warehouse_operating_unit(self):
-# picking_type = self.picking_type_id
-# if picking_type:
-# if picking_type.warehouse_id and\
-# picking_type.warehouse_id.operating_unit_id\
-# and self.operating_unit_id and\
-# picking_type.warehouse_id.operating_unit_id !=\
-# self.operating_unit_id:
-# raise UserError(_('Configuration error!\nThe\
-# Quotation / Purchase Order and the Warehouse of picking type\
-# must belong to the same Operating Unit.'))
+ picking_type_id = fields.Many2one('stock.picking.type', 'Deliver To',
+ help="This will determine picking type "
+ "of incoming shipment",
+ required=True,
+ states={'confirmed':
+ [('readonly', True)],
+ 'approved': [('readonly', True)],
+ 'done': [('readonly', True)]},
+ default=_default_picking_type)
+
+ @api.one
+ @api.constrains('operating_unit_id', 'picking_type_id')
+ def _check_warehouse_operating_unit(self):
+ picking_type = self.picking_type_id
+ if picking_type:
+ if picking_type.warehouse_id and\
+ picking_type.warehouse_id.operating_unit_id\
+ and self.operating_unit_id and\
+ picking_type.warehouse_id.operating_unit_id !=\
+ self.operating_unit_id:
+ raise Warning(_('Configuration error!\nThe\
+ Quotation / Purchase Order and the Warehouse of picking type\
+ must belong to the same Operating Unit.'))
@api.one
@api.constrains('operating_unit_id', 'requesting_operating_unit_id',
@@ -41,30 +63,39 @@ class PurchaseOrder(models.Model):
def _check_company_operating_unit(self):
if self.company_id and self.operating_unit_id and\
self.company_id != self.operating_unit_id.company_id:
- raise UserError(_('Configuration error!\nThe Company in the\
+ raise Warning(_('Configuration error!\nThe Company in the\
Purchase Order and in the Operating Unit must be the same.'))
- @api.onchange('requesting_operating_unit_id', 'operating_unit_id')
- def onchange_operating_unit_id(self):
- pick_type = self.env['stock.picking.type']
- location_obj = self.env['stock.location']
- if not self.requesting_operating_unit_id or not self.operating_unit_id:
- return {}
- request_locations =\
- location_obj.search([('operating_unit_id', '=',
- self.requesting_operating_unit_id.id)])
- picking_types =\
- pick_type.search([('default_location_dest_id', 'in',
- request_locations.ids)], limit=1)
- if picking_types:
- self.picking_type_id = picking_types.id
+ @api.onchange('operating_unit_id')
+ def _onchange_operating_unit_id(self):
+ type_obj = self.env['stock.picking.type']
+ if self.operating_unit_id:
+ types = type_obj.search([('code', '=', 'incoming'),
+ ('warehouse_id.operating_unit_id', '=',
+ self.operating_unit_id.id)])
+ if types:
+ self.picking_type_id = types[:1]
+ else:
+ raise exceptions.Warning(_("No Warehouse found with the "
+ "Operating Unit indicated in the "
+ "Purchase Order!"))
@api.model
def _prepare_picking(self):
- res = super(PurchaseOrder, self)._prepare_picking()
- res['operating_unit_id'] = self.operating_unit_id and\
+ picking_vals = super(PurchaseOrder, self)._prepare_picking()
+ picking_vals['operating_unit_id'] = self.operating_unit_id and\
self.operating_unit_id.id
- return res
+ return picking_vals
+
+ @api.one
+ @api.constrains('invoice_ids')
+ def _check_invoice_ou(self):
+ for po in self:
+ for invoice in po.invoice_ids:
+ if invoice.operating_unit_id != po.operating_unit_id:
+ raise Warning(_('The operating unit of the purchase order '
+ 'must be the same as in the '
+ 'associated invoices.'))
class PurchaseOrderLine(models.Model):
@@ -73,3 +104,15 @@ class PurchaseOrderLine(models.Model):
operating_unit_id = fields.Many2one('operating.unit',
related='order_id.operating_unit_id',
string='Operating Unit', readonly=True)
+
+ @api.one
+ @api.constrains('invoice_lines')
+ def _check_invoice_ou(self):
+ for line in self:
+ for inv_line in line.invoice_lines:
+ if inv_line.invoice_id and \
+ inv_line.invoice_id.operating_unit_id != \
+ line.operating_unit_id:
+ raise Warning(_('The operating unit of the purchase order '
+ 'must be the same as in the '
+ 'associated invoices.'))
diff --git a/purchase_operating_unit/tests/test_po_security.py b/purchase_operating_unit/tests/test_po_security.py
index 293f7b2b8c..0ca2888caa 100644
--- a/purchase_operating_unit/tests/test_po_security.py
+++ b/purchase_operating_unit/tests/test_po_security.py
@@ -22,7 +22,7 @@ def test_po_ou_security(self):
self.StockPicking.sudo(self.user2_id).\
search([('id', 'in', self.purchase1.picking_ids.ids)]).ids
self.assertEqual(picking_ids, [])
- # User 2 cannot list the invoice that was created from PO 2
+ # User 2 cannot list the invoice that was created from PO 1
invoice_ids = self.AccountInvoice.sudo(self.user2_id).\
search([('purchase_id', '=', self.purchase1.id)]).ids
self.assertEqual(invoice_ids, [])
@@ -37,7 +37,7 @@ def test_po_ou_security(self):
self.StockPicking.sudo(self.user1_id).\
search([('id', 'in', self.purchase1.picking_ids.ids)]).ids
self.assertNotEqual(picking_ids, [])
- # User 1 can list the invoice that was created from PO 2
+# # User 1 can list the invoice that was created from PO 2
invoice_ids = self.AccountInvoice.sudo(self.user1_id).\
search([('purchase_id', '=', self.purchase1.id)]).ids
self.assertNotEqual(invoice_ids, [])
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
index b352e5d863..1952908e7b 100644
--- a/purchase_operating_unit/tests/test_purchase_operating_unit.py
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -30,6 +30,8 @@ def setUp(self):
self.product1 = self.env.ref('product.product_product_7')
self.product2 = self.env.ref('product.product_product_9')
self.product3 = self.env.ref('product.product_product_11')
+ # Account
+ self.account = self.env.ref('l10n_generic_coa.conf_a_pay')
# Create users
self.user1_id = self._create_user('user_1',
[self.group_purchase_user,
@@ -46,6 +48,7 @@ def setUp(self):
(self.product2, 500),
(self.product3, 800)])
self.purchase1.sudo(self.user1_id).button_confirm()
+ self._create_invoice(self.purchase1, self.partner1, self.account)
def _create_user(self, login, groups, company, operating_units):
""" Create a user."""
@@ -79,10 +82,28 @@ def _create_purchase(self, user_id, line_products):
'date_planned': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
}
lines.append((0, 0, line_values))
- return self.PurchaseOrder.sudo(user_id).create({
+ purchase = self.PurchaseOrder.sudo(user_id).create({
'operating_unit_id': self.ou1.id,
'requesting_operating_unit_id': self.ou1.id,
'partner_id': self.partner1.id,
'order_line': lines,
'company_id': self.company1.id,
})
+ return purchase
+
+ def _create_invoice(self, purchase, partner, account):
+ """ Create a vendor invoice for the purchase order."""
+ invoice_vals = {
+ 'purchase_id': purchase.id,
+ 'partner_id': partner.id,
+ 'account_id': account.id,
+ 'type': 'in_invoice',
+ }
+ purchase_context = {
+ 'active_id': purchase.id,
+ 'active_ids': purchase.ids,
+ 'active_model': 'purchase.order',
+ }
+ self.env['account.invoice'].with_context(purchase_context).\
+ create(invoice_vals)
+ return True
From 4d24afc04f702b3c11515fc56154e3b04f7afcc5 Mon Sep 17 00:00:00 2001
From: jbeficent
Date: Thu, 6 Oct 2016 10:31:48 +0200
Subject: [PATCH 05/56] create PO from procurement
---
purchase_operating_unit/README.rst | 5 -
purchase_operating_unit/__openerp__.py | 8 +-
.../demo/purchase_order_demo.xml | 48 ++++---
purchase_operating_unit/models/procurement.py | 21 +--
purchase_operating_unit/models/purchase.py | 123 ++++++++++--------
.../security/purchase_security.xml | 46 ++++---
.../views/purchase_order_line_view.xml | 68 +++++-----
.../views/purchase_order_view.xml | 78 ++++++-----
8 files changed, 197 insertions(+), 200 deletions(-)
diff --git a/purchase_operating_unit/README.rst b/purchase_operating_unit/README.rst
index a738cb85da..cf6cc99ff7 100644
--- a/purchase_operating_unit/README.rst
+++ b/purchase_operating_unit/README.rst
@@ -12,11 +12,6 @@ This module introduces the following features:
- The operating unit is copied to the stock picking.
- It implements user's security rules.
-
-Configuration
-=============
-
-
Usage
=====
diff --git a/purchase_operating_unit/__openerp__.py b/purchase_operating_unit/__openerp__.py
index 3384aaf801..3c3f7ff812 100644
--- a/purchase_operating_unit/__openerp__.py
+++ b/purchase_operating_unit/__openerp__.py
@@ -1,15 +1,15 @@
# -*- coding: utf-8 -*-
-# © 2015 Eficent Business and IT Consulting Services S.L.
+# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
{
"name": "Operating Unit in Purchase Orders",
- "summary": "An operating unit (OU) is an organizational entity part of a\
- company",
+ "summary": "An operating unit (OU) is an organizational entity part of a "
+ "company",
"version": "9.0.1.0.0",
- "author": "Eficent Business and IT Consulting Services S.L., "
+ "author": "Eficent, "
"Serpent Consulting Services Pvt. Ltd.,"
"Odoo Community Association (OCA)",
"website": "http://www.eficent.com",
diff --git a/purchase_operating_unit/demo/purchase_order_demo.xml b/purchase_operating_unit/demo/purchase_order_demo.xml
index fc427bfe36..1db5f80a9f 100644
--- a/purchase_operating_unit/demo/purchase_order_demo.xml
+++ b/purchase_operating_unit/demo/purchase_order_demo.xml
@@ -1,34 +1,32 @@
-
-
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
+
diff --git a/purchase_operating_unit/models/procurement.py b/purchase_operating_unit/models/procurement.py
index bd98de86bc..038657ddcd 100644
--- a/purchase_operating_unit/models/procurement.py
+++ b/purchase_operating_unit/models/procurement.py
@@ -3,9 +3,8 @@
# - Jordi Ballester Alomar
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-from openerp import api, models
-from openerp.tools.translate import _
-from openerp.exceptions import UserError
+from openerp import _, api, models
+from openerp.exceptions import ValidationError
class ProcurementOrder(models.Model):
@@ -14,13 +13,15 @@ class ProcurementOrder(models.Model):
@api.one
@api.constrains('purchase_line_id')
def _check_purchase_order_operating_unit(self):
- purchase = self.purchase_line_id.purchase_id
- if purchase and \
- purchase.operating_unit_id !=\
- self.location_id.operating_unit_id:
- raise UserError(_('Configuration error!\nThe Quotation / Purchase\
- Order and the Procurement Order must belong to the\
- same Operating Unit.'))
+ purchase = self.purchase_line_id.order_id
+ location = self.location_id
+ if (purchase and
+ purchase.operating_unit_id != location.operating_unit_id):
+ raise ValidationError(
+ _('Configuration error\nThe Quotation / Purchase Order and '
+ 'the Procurement Order must belong to the same '
+ 'Operating Unit.')
+ )
@api.multi
def _prepare_purchase_order(self, partner):
diff --git a/purchase_operating_unit/models/purchase.py b/purchase_operating_unit/models/purchase.py
index 9d142b31b9..69949fe142 100644
--- a/purchase_operating_unit/models/purchase.py
+++ b/purchase_operating_unit/models/purchase.py
@@ -3,8 +3,8 @@
# - Jordi Ballester Alomar
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-from openerp import _, api, exceptions, fields, models
-from openerp.exceptions import Warning
+from openerp import _, api, fields, models
+from openerp.exceptions import ValidationError, UserError
class PurchaseOrder(models.Model):
@@ -15,7 +15,8 @@ def _default_picking_type(self):
res = super(PurchaseOrder, self)._default_picking_type()
type_obj = self.env['stock.picking.type']
operating_unit = self.env['res.users'].operating_unit_default_get(
- self._uid)
+ self.env.uid
+ )
types = type_obj.search([('code', '=', 'incoming'),
('warehouse_id.operating_unit_id', '=',
operating_unit.id)])
@@ -23,48 +24,57 @@ def _default_picking_type(self):
res = types[:1].id
return res
- operating_unit_id = fields.Many2one('operating.unit', 'Operating Unit',
- default=lambda self:
- self.env['res.users'].
- operating_unit_default_get(self._uid))
- requesting_operating_unit_id =\
- fields.Many2one('operating.unit', 'Requesting Operating Unit',
- default=lambda self:
- self.env['res.users'].
- operating_unit_default_get(self._uid))
+ operating_unit_id = fields.Many2one(
+ comodel_name='operating.unit',
+ string='Operating Unit',
+ default=lambda self: (self.env['res.users'].
+ operating_unit_default_get(self.env.uid))
+ )
+ requesting_operating_unit_id = fields.Many2one(
+ comodel_name='operating.unit',
+ string='Requesting Operating Unit',
+ default=lambda self: (self.env['res.users'].
+ operating_unit_default_get(self.env.uid))
+ )
- picking_type_id = fields.Many2one('stock.picking.type', 'Deliver To',
- help="This will determine picking type "
- "of incoming shipment",
- required=True,
- states={'confirmed':
- [('readonly', True)],
- 'approved': [('readonly', True)],
- 'done': [('readonly', True)]},
- default=_default_picking_type)
+ picking_type_id = fields.Many2one(
+ comodel_name='stock.picking.type',
+ string='Deliver To',
+ help="This will determine picking type of incoming shipment",
+ required=True,
+ states={'confirmed': [('readonly', True)],
+ 'approved': [('readonly', True)],
+ 'done': [('readonly', True)]},
+ default=lambda self: self._default_picking_type(),
+ )
- @api.one
@api.constrains('operating_unit_id', 'picking_type_id')
def _check_warehouse_operating_unit(self):
- picking_type = self.picking_type_id
- if picking_type:
- if picking_type.warehouse_id and\
- picking_type.warehouse_id.operating_unit_id\
- and self.operating_unit_id and\
- picking_type.warehouse_id.operating_unit_id !=\
- self.operating_unit_id:
- raise Warning(_('Configuration error!\nThe\
- Quotation / Purchase Order and the Warehouse of picking type\
- must belong to the same Operating Unit.'))
+ for record in self:
+ picking_type = record.picking_type_id
+ if not record.picking_type_id:
+ continue
+ warehouse = picking_type.warehouse_id
+ if (picking_type.warehouse_id and
+ picking_type.warehouse_id.operating_unit_id and
+ record.operating_unit_id and
+ warehouse.operating_unit_id != record.operating_unit_id):
+ raise ValidationError(
+ _('Configuration error\nThe Quotation / Purchase Order '
+ 'and the Warehouse of picking type must belong to the '
+ 'same Operating Unit.')
+ )
- @api.one
@api.constrains('operating_unit_id', 'requesting_operating_unit_id',
'company_id')
def _check_company_operating_unit(self):
- if self.company_id and self.operating_unit_id and\
- self.company_id != self.operating_unit_id.company_id:
- raise Warning(_('Configuration error!\nThe Company in the\
- Purchase Order and in the Operating Unit must be the same.'))
+ for record in self:
+ if (record.company_id and record.operating_unit_id and
+ record.company_id != record.operating_unit_id.company_id):
+ raise ValidationError(
+ _('Configuration error\nThe Company in the Purchase Order '
+ 'and in the Operating Unit must be the same.')
+ )
@api.onchange('operating_unit_id')
def _onchange_operating_unit_id(self):
@@ -76,43 +86,42 @@ def _onchange_operating_unit_id(self):
if types:
self.picking_type_id = types[:1]
else:
- raise exceptions.Warning(_("No Warehouse found with the "
- "Operating Unit indicated in the "
- "Purchase Order!"))
+ raise UserError(
+ _("No Warehouse found with the Operating Unit indicated "
+ "in the Purchase Order")
+ )
@api.model
def _prepare_picking(self):
picking_vals = super(PurchaseOrder, self)._prepare_picking()
- picking_vals['operating_unit_id'] = self.operating_unit_id and\
- self.operating_unit_id.id
+ picking_vals['operating_unit_id'] = self.operating_unit_id.id
return picking_vals
- @api.one
- @api.constrains('invoice_ids')
+ @api.constrains('invoice_ids', 'operating_unit_id')
def _check_invoice_ou(self):
for po in self:
for invoice in po.invoice_ids:
if invoice.operating_unit_id != po.operating_unit_id:
- raise Warning(_('The operating unit of the purchase order '
- 'must be the same as in the '
- 'associated invoices.'))
+ raise ValidationError(
+ _('The operating unit of the purchase order must '
+ 'be the same as in the associated invoices.')
+ )
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
- operating_unit_id = fields.Many2one('operating.unit',
- related='order_id.operating_unit_id',
+ operating_unit_id = fields.Many2one(related='order_id.operating_unit_id',
string='Operating Unit', readonly=True)
- @api.one
- @api.constrains('invoice_lines')
+ @api.constrains('operating_unit_id', 'invoice_lines')
def _check_invoice_ou(self):
for line in self:
for inv_line in line.invoice_lines:
- if inv_line.invoice_id and \
- inv_line.invoice_id.operating_unit_id != \
- line.operating_unit_id:
- raise Warning(_('The operating unit of the purchase order '
- 'must be the same as in the '
- 'associated invoices.'))
+ invoice_operating_unit = inv_line.invoice_id.operating_unit_id
+ if (inv_line.invoice_id and
+ invoice_operating_unit != line.operating_unit_id):
+ raise ValidationError(
+ _('The operating unit of the purchase order must '
+ 'be the same as in the associated invoices.')
+ )
diff --git a/purchase_operating_unit/security/purchase_security.xml b/purchase_operating_unit/security/purchase_security.xml
index 14cdd36be4..f5ed96aaee 100644
--- a/purchase_operating_unit/security/purchase_security.xml
+++ b/purchase_operating_unit/security/purchase_security.xml
@@ -1,28 +1,26 @@
-
-
+
-
-
- ['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]
- PO's from allowed operating units
-
-
-
-
-
-
+
+
+ ['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]
+ PO's from allowed operating units
+
+
+
+
+
+
-
-
- ['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]
- PO lines from allowed operating units
-
-
-
-
-
-
+
+
+ ['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]
+ PO lines from allowed operating units
+
+
+
+
+
+
-
-
+
diff --git a/purchase_operating_unit/views/purchase_order_line_view.xml b/purchase_operating_unit/views/purchase_order_line_view.xml
index 283a8d9bc5..b0734875dc 100644
--- a/purchase_operating_unit/views/purchase_order_line_view.xml
+++ b/purchase_operating_unit/views/purchase_order_line_view.xml
@@ -1,43 +1,41 @@
-
-
+
-
- purchase_order_line_tree
- purchase.order.line
-
-
-
-
-
+
+ purchase_order_line_tree
+ purchase.order.line
+
+
+
+
-
+
+
-
- purchase_order_line_form
- purchase.order.line
-
-
-
-
-
+
+ purchase_order_line_form
+ purchase.order.line
+
+
+
+
-
+
+
-
- purchase_order_line_search
- purchase.order.line
-
-
-
-
-
-
-
-
+
+ purchase_order_line_search
+ purchase.order.line
+
+
+
+
+
+
+
-
+
+
-
-
+
diff --git a/purchase_operating_unit/views/purchase_order_view.xml b/purchase_operating_unit/views/purchase_order_view.xml
index cb3d7d9e4b..ee1f25e290 100644
--- a/purchase_operating_unit/views/purchase_order_view.xml
+++ b/purchase_operating_unit/views/purchase_order_view.xml
@@ -1,52 +1,50 @@
-
-
+
-
- purchase_order_tree
- purchase.order
-
-
-
-
-
+
+ purchase_order_tree
+ purchase.order
+
+
+
+
-
+
+
-
- purchase_order_form
- purchase.order
-
-
-
-
+
+ purchase_order_form
+ purchase.order
+
+
+
+
-
+
-
-
- {'operating_unit_id': operating_unit_id}
-
+
+
+ {'operating_unit_id': operating_unit_id}
+
-
-
+
+
-
- view_purchase_order_filter
- purchase.order
-
-
-
-
-
-
-
-
+
+ view_purchase_order_filter
+ purchase.order
+
+
+
+
+
+
+
-
+
+
-
-
+
From 080e65c2a61d5d3527c9718e49958882a10f9a48 Mon Sep 17 00:00:00 2001
From: ahenriquez
Date: Tue, 31 Jan 2017 10:02:04 +0100
Subject: [PATCH 06/56] [MIG] purchase_operating_unit: Migrated to 10.0
---
purchase_operating_unit/README.rst | 5 +----
.../{__openerp__.py => __manifest__.py} | 4 ++--
purchase_operating_unit/models/__init__.py | 4 ++--
purchase_operating_unit/models/invoice.py | 17 ++++++++++++++---
purchase_operating_unit/models/procurement.py | 8 ++++----
purchase_operating_unit/models/purchase.py | 18 ++++--------------
purchase_operating_unit/tests/__init__.py | 4 ++--
.../tests/test_po_security.py | 6 +++---
.../tests/test_purchase_operating_unit.py | 8 ++++----
.../views/purchase_order_view.xml | 5 -----
10 files changed, 36 insertions(+), 43 deletions(-)
rename purchase_operating_unit/{__openerp__.py => __manifest__.py} (90%)
diff --git a/purchase_operating_unit/README.rst b/purchase_operating_unit/README.rst
index cf6cc99ff7..e68b754012 100644
--- a/purchase_operating_unit/README.rst
+++ b/purchase_operating_unit/README.rst
@@ -12,12 +12,9 @@ This module introduces the following features:
- The operating unit is copied to the stock picking.
- It implements user's security rules.
-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/213/9.0
+ :target: https://runbot.odoo-community.org/runbot/213/10.0
Bug Tracker
===========
diff --git a/purchase_operating_unit/__openerp__.py b/purchase_operating_unit/__manifest__.py
similarity index 90%
rename from purchase_operating_unit/__openerp__.py
rename to purchase_operating_unit/__manifest__.py
index 3c3f7ff812..11a2f72dc8 100644
--- a/purchase_operating_unit/__openerp__.py
+++ b/purchase_operating_unit/__manifest__.py
@@ -1,14 +1,14 @@
# -*- coding: utf-8 -*-
# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
-# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
{
"name": "Operating Unit in Purchase Orders",
"summary": "An operating unit (OU) is an organizational entity part of a "
"company",
- "version": "9.0.1.0.0",
+ "version": "10.0.1.0.0",
"author": "Eficent, "
"Serpent Consulting Services Pvt. Ltd.,"
"Odoo Community Association (OCA)",
diff --git a/purchase_operating_unit/models/__init__.py b/purchase_operating_unit/models/__init__.py
index eeebb4267f..df20d9dbe3 100644
--- a/purchase_operating_unit/models/__init__.py
+++ b/purchase_operating_unit/models/__init__.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
-# © 2015 Eficent Business and IT Consulting Services S.L.
+# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
-# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import purchase
from . import procurement
diff --git a/purchase_operating_unit/models/invoice.py b/purchase_operating_unit/models/invoice.py
index eff0a4266c..3505850814 100644
--- a/purchase_operating_unit/models/invoice.py
+++ b/purchase_operating_unit/models/invoice.py
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
-# © 2015 Eficent Business and IT Consulting Services S.L.
+# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
-# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-from openerp import api, models
+from odoo import api, models
class AccountInvoice(models.Model):
@@ -19,3 +19,14 @@ def purchase_order_change(self):
# Assign OU from PO to Invoice
self.operating_unit_id = self.purchase_id.operating_unit_id.id
return super(AccountInvoice, self).purchase_order_change()
+
+ @api.onchange('operating_unit_id')
+ def _onchange_allowed_purchase_ids(self):
+ '''
+ Show only the purchase orders that have the same operating unit
+ '''
+ result = super(AccountInvoice, self)._onchange_allowed_purchase_ids()
+
+ result['domain']['purchase_id'] += [('operating_unit_id', '=',
+ self.operating_unit_id.id)]
+ return result
diff --git a/purchase_operating_unit/models/procurement.py b/purchase_operating_unit/models/procurement.py
index 038657ddcd..b6874bbb76 100644
--- a/purchase_operating_unit/models/procurement.py
+++ b/purchase_operating_unit/models/procurement.py
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
-# © 2015 Eficent Business and IT Consulting Services S.L.
+# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
-# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-from openerp import _, api, models
-from openerp.exceptions import ValidationError
+from odoo import _, api, models
+from odoo.exceptions import ValidationError
class ProcurementOrder(models.Model):
diff --git a/purchase_operating_unit/models/purchase.py b/purchase_operating_unit/models/purchase.py
index 69949fe142..ba556dece5 100644
--- a/purchase_operating_unit/models/purchase.py
+++ b/purchase_operating_unit/models/purchase.py
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
-# © 2015 Eficent Business and IT Consulting Services S.L.
+# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
-# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-from openerp import _, api, fields, models
-from openerp.exceptions import ValidationError, UserError
+from odoo import _, api, fields, models
+from odoo.exceptions import ValidationError, UserError
class PurchaseOrder(models.Model):
@@ -97,16 +97,6 @@ def _prepare_picking(self):
picking_vals['operating_unit_id'] = self.operating_unit_id.id
return picking_vals
- @api.constrains('invoice_ids', 'operating_unit_id')
- def _check_invoice_ou(self):
- for po in self:
- for invoice in po.invoice_ids:
- if invoice.operating_unit_id != po.operating_unit_id:
- raise ValidationError(
- _('The operating unit of the purchase order must '
- 'be the same as in the associated invoices.')
- )
-
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
diff --git a/purchase_operating_unit/tests/__init__.py b/purchase_operating_unit/tests/__init__.py
index cb1343a28e..de41426d68 100644
--- a/purchase_operating_unit/tests/__init__.py
+++ b/purchase_operating_unit/tests/__init__.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
-# © 2015 Eficent Business and IT Consulting Services S.L.
+# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
-# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import test_purchase_operating_unit
from . import test_po_security
diff --git a/purchase_operating_unit/tests/test_po_security.py b/purchase_operating_unit/tests/test_po_security.py
index 0ca2888caa..bd54d6a171 100644
--- a/purchase_operating_unit/tests/test_po_security.py
+++ b/purchase_operating_unit/tests/test_po_security.py
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
-# © 2015 Eficent Business and IT Consulting Services S.L.
+# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
-# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-from openerp.addons.purchase_operating_unit.tests import\
+from odoo.addons.purchase_operating_unit.tests import\
test_purchase_operating_unit as test_po_ou
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
index 1952908e7b..63e4198f54 100644
--- a/purchase_operating_unit/tests/test_purchase_operating_unit.py
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
-# © 2015 Eficent Business and IT Consulting Services S.L.
+# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
-# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
import time
-from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
-from openerp.addons.purchase.tests import test_purchase_order
+from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
+from odoo.addons.purchase.tests import test_purchase_order
class TestPurchaseOperatingUnit(test_purchase_order.TestPurchaseOrder):
diff --git a/purchase_operating_unit/views/purchase_order_view.xml b/purchase_operating_unit/views/purchase_order_view.xml
index ee1f25e290..a1f9b73e2b 100644
--- a/purchase_operating_unit/views/purchase_order_view.xml
+++ b/purchase_operating_unit/views/purchase_order_view.xml
@@ -19,17 +19,12 @@
-
-
{'operating_unit_id': operating_unit_id}
-
-
-
From c276181f5b643b353bd738385654836737559d9e Mon Sep 17 00:00:00 2001
From: Darshan Patel
Date: Tue, 4 Jul 2017 14:48:56 +0530
Subject: [PATCH 07/56] [FIX] readonly on OU
---
purchase_operating_unit/__manifest__.py | 2 +-
purchase_operating_unit/models/purchase.py | 9 +++++++++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/purchase_operating_unit/__manifest__.py b/purchase_operating_unit/__manifest__.py
index 11a2f72dc8..5b060356e8 100644
--- a/purchase_operating_unit/__manifest__.py
+++ b/purchase_operating_unit/__manifest__.py
@@ -8,7 +8,7 @@
"name": "Operating Unit in Purchase Orders",
"summary": "An operating unit (OU) is an organizational entity part of a "
"company",
- "version": "10.0.1.0.0",
+ "version": "10.0.1.1.0",
"author": "Eficent, "
"Serpent Consulting Services Pvt. Ltd.,"
"Odoo Community Association (OCA)",
diff --git a/purchase_operating_unit/models/purchase.py b/purchase_operating_unit/models/purchase.py
index ba556dece5..3e9fc4042d 100644
--- a/purchase_operating_unit/models/purchase.py
+++ b/purchase_operating_unit/models/purchase.py
@@ -24,15 +24,24 @@ def _default_picking_type(self):
res = types[:1].id
return res
+ READONLY_STATES = {
+ 'purchase': [('readonly', True)],
+ 'done': [('readonly', True)],
+ 'cancel': [('readonly', True)],
+ }
+
operating_unit_id = fields.Many2one(
comodel_name='operating.unit',
string='Operating Unit',
+ states=READONLY_STATES,
default=lambda self: (self.env['res.users'].
operating_unit_default_get(self.env.uid))
)
+
requesting_operating_unit_id = fields.Many2one(
comodel_name='operating.unit',
string='Requesting Operating Unit',
+ states=READONLY_STATES,
default=lambda self: (self.env['res.users'].
operating_unit_default_get(self.env.uid))
)
From e696df95d515e7233f3662281f9fd7cf585f7d69 Mon Sep 17 00:00:00 2001
From: aheficent
Date: Wed, 22 Nov 2017 18:20:45 +0100
Subject: [PATCH 08/56] [FIX] when the procurement location is not internal the
PO may belong to an OU
---
purchase_operating_unit/__manifest__.py | 2 +-
purchase_operating_unit/models/procurement.py | 25 +++++++++++--------
purchase_operating_unit/models/purchase.py | 2 +-
3 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/purchase_operating_unit/__manifest__.py b/purchase_operating_unit/__manifest__.py
index 5b060356e8..e7ac4dc1b2 100644
--- a/purchase_operating_unit/__manifest__.py
+++ b/purchase_operating_unit/__manifest__.py
@@ -8,7 +8,7 @@
"name": "Operating Unit in Purchase Orders",
"summary": "An operating unit (OU) is an organizational entity part of a "
"company",
- "version": "10.0.1.1.0",
+ "version": "10.0.1.1.1",
"author": "Eficent, "
"Serpent Consulting Services Pvt. Ltd.,"
"Odoo Community Association (OCA)",
diff --git a/purchase_operating_unit/models/procurement.py b/purchase_operating_unit/models/procurement.py
index b6874bbb76..2cd8e730d8 100644
--- a/purchase_operating_unit/models/procurement.py
+++ b/purchase_operating_unit/models/procurement.py
@@ -10,18 +10,21 @@
class ProcurementOrder(models.Model):
_inherit = 'procurement.order'
- @api.one
- @api.constrains('purchase_line_id')
+ @api.multi
+ @api.constrains('purchase_line_id', 'location_id')
def _check_purchase_order_operating_unit(self):
- purchase = self.purchase_line_id.order_id
- location = self.location_id
- if (purchase and
- purchase.operating_unit_id != location.operating_unit_id):
- raise ValidationError(
- _('Configuration error\nThe Quotation / Purchase Order and '
- 'the Procurement Order must belong to the same '
- 'Operating Unit.')
- )
+ for proc in self:
+ if not proc.purchase_line_id:
+ continue
+ ou = proc.location_id.operating_unit_id
+ order_ou = proc.purchase_line_id.operating_unit_id
+ if (ou != order_ou and
+ proc.location_id.usage not in ('supplier', 'customer')):
+ raise ValidationError(
+ _('Configuration error. The Quotation / Purchase Order '
+ 'and the Procurement Order must belong to the same '
+ 'Operating Unit.')
+ )
@api.multi
def _prepare_purchase_order(self, partner):
diff --git a/purchase_operating_unit/models/purchase.py b/purchase_operating_unit/models/purchase.py
index 3e9fc4042d..b7f9a01933 100644
--- a/purchase_operating_unit/models/purchase.py
+++ b/purchase_operating_unit/models/purchase.py
@@ -113,7 +113,7 @@ class PurchaseOrderLine(models.Model):
operating_unit_id = fields.Many2one(related='order_id.operating_unit_id',
string='Operating Unit', readonly=True)
- @api.constrains('operating_unit_id', 'invoice_lines')
+ @api.constrains('order_id.operating_unit_id', 'invoice_lines')
def _check_invoice_ou(self):
for line in self:
for inv_line in line.invoice_lines:
From e573c3dec8f1a4e776b0fe15e149245dbd5706e7 Mon Sep 17 00:00:00 2001
From: aaron
Date: Mon, 11 Jun 2018 12:02:48 +0200
Subject: [PATCH 09/56] [FIX]PYLINT mainly
---
purchase_operating_unit/tests/test_po_security.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/purchase_operating_unit/tests/test_po_security.py b/purchase_operating_unit/tests/test_po_security.py
index bd54d6a171..89d0da8ea9 100644
--- a/purchase_operating_unit/tests/test_po_security.py
+++ b/purchase_operating_unit/tests/test_po_security.py
@@ -4,7 +4,7 @@
# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo.addons.purchase_operating_unit.tests import\
- test_purchase_operating_unit as test_po_ou
+ test_purchase_operating_unit as test_po_ou # noqa
class TestPoSecurity(test_po_ou.TestPurchaseOperatingUnit):
From 9e6f2d532adc9d05a01192444e0de5491c81e726 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Be=C3=B1at=20Jimenez?=
Date: Tue, 18 Dec 2018 10:11:05 +0100
Subject: [PATCH 10/56] [MIG] purchase_operating_unit: Migration to v12.0
---
purchase_operating_unit/README.rst | 90 +++-
purchase_operating_unit/__init__.py | 3 -
purchase_operating_unit/__manifest__.py | 11 +-
.../demo/purchase_order_demo.xml | 4 +
purchase_operating_unit/models/__init__.py | 9 +-
.../models/{invoice.py => account_invoice.py} | 17 +-
purchase_operating_unit/models/procurement.py | 38 --
.../models/{purchase.py => purchase_order.py} | 22 +-
.../readme/CONTRIBUTORS.rst | 3 +
.../readme/DESCRIPTION.rst | 6 +
purchase_operating_unit/readme/ROADMAP.rst | 3 +
purchase_operating_unit/readme/USAGE.rst | 6 +
.../security/purchase_security.xml | 8 +-
.../static/description/index.html | 447 ++++++++++++++++++
purchase_operating_unit/tests/__init__.py | 4 -
.../tests/test_po_security.py | 4 +-
.../tests/test_purchase_operating_unit.py | 7 +-
.../views/purchase_order_line_view.xml | 21 +-
.../views/purchase_order_view.xml | 25 +-
19 files changed, 603 insertions(+), 125 deletions(-)
rename purchase_operating_unit/models/{invoice.py => account_invoice.py} (66%)
delete mode 100644 purchase_operating_unit/models/procurement.py
rename purchase_operating_unit/models/{purchase.py => purchase_order.py} (81%)
create mode 100644 purchase_operating_unit/readme/CONTRIBUTORS.rst
create mode 100644 purchase_operating_unit/readme/DESCRIPTION.rst
create mode 100644 purchase_operating_unit/readme/ROADMAP.rst
create mode 100644 purchase_operating_unit/readme/USAGE.rst
create mode 100644 purchase_operating_unit/static/description/index.html
diff --git a/purchase_operating_unit/README.rst b/purchase_operating_unit/README.rst
index e68b754012..53cc27fdbd 100644
--- a/purchase_operating_unit/README.rst
+++ b/purchase_operating_unit/README.rst
@@ -1,56 +1,98 @@
-.. image:: https://img.shields.io/badge/license-AGPLv3-blue.svg
- :target: https://www.gnu.org/licenses/lgpl.html
- :alt: License: LGPL-3
-
-===============================
-Purchase with Operating Units
-===============================
+=================================
+Operating Unit in Purchase Orders
+=================================
+
+.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! This file is generated by oca-gen-addon-readme !!
+ !! changes will be overwritten. !!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
+ :target: https://odoo-community.org/page/development-status
+ :alt: Beta
+.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
+ :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
+ :alt: License: LGPL-3
+.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Foperating--unit-lightgray.png?logo=github
+ :target: https://github.com/OCA/operating-unit/tree/12.0/purchase_operating_unit
+ :alt: OCA/operating-unit
+.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
+ :target: https://translation.odoo-community.org/projects/operating-unit-12-0/operating-unit-12-0-purchase_operating_unit
+ :alt: Translate me on Weblate
+.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
+ :target: https://runbot.odoo-community.org/runbot/213/12.0
+ :alt: Try me on Runbot
+
+|badge1| |badge2| |badge3| |badge4| |badge5|
This module introduces the following features:
+
- It introduces the operating unit to the purchase order.
- The operating unit is copied to the invoice.
- The operating unit is copied to the stock picking.
- It implements user's security rules.
-.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
- :alt: Try me on Runbot
- :target: https://runbot.odoo-community.org/runbot/213/10.0
+**Table of contents**
+
+.. contents::
+ :local:
+
+Usage
+=====
+
+#. Create a PO: the Default Operating Unit is assigned to the PO. If you want,
+ you can change to another Operating Unit.
+#. Validate the PO: the Operating Unit is propagated to the Pickings and
+ Invoices.
+#. From the invoice, it is not possible to change the Operating Unit, it has to
+ be the same as the one of the PO.
+
+Known issues / Roadmap
+======================
+
+Procurement Orders were removed. Procurement Operating Unit module is
+deprecated. Stock Operating Unit ensures consistency between the operating unit
+from different models.
Bug Tracker
===========
-Bugs are tracked on `GitHub 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.
+Bugs are tracked on `GitHub 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 `_.
+Do not contact contributors directly about support or help with technical issues.
Credits
=======
-Images
-------
+Authors
+~~~~~~~
-* Odoo Community Association: `Icon `_.
+* Eficent
+* Serpent Consulting Services Pvt. Ltd.
Contributors
-------------
+~~~~~~~~~~~~
* Jordi Ballester Alomar
* Aaron Henriquez
* Sudhir Arya
-Maintainer
-----------
+Maintainers
+~~~~~~~~~~~
+
+This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
- :target: http://odoo-community.org
-
-This module is maintained by the OCA.
+ :target: https://odoo-community.org
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 http://odoo-community.org.
+This module is part of the `OCA/operating-unit `_ project on GitHub.
+
+You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/purchase_operating_unit/__init__.py b/purchase_operating_unit/__init__.py
index cf1a072540..133f68732d 100644
--- a/purchase_operating_unit/__init__.py
+++ b/purchase_operating_unit/__init__.py
@@ -1,5 +1,2 @@
-# -*- coding: utf-8 -*-
-# © 2016 Eficent Business and IT Consulting Services S.L.
-# © 2016 Serpent Consulting Services Pvt. Ltd.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import models
diff --git a/purchase_operating_unit/__manifest__.py b/purchase_operating_unit/__manifest__.py
index e7ac4dc1b2..0327137673 100644
--- a/purchase_operating_unit/__manifest__.py
+++ b/purchase_operating_unit/__manifest__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
@@ -6,15 +5,15 @@
{
"name": "Operating Unit in Purchase Orders",
- "summary": "An operating unit (OU) is an organizational entity part of a "
- "company",
- "version": "10.0.1.1.1",
+ "summary": "Adds the concecpt of operating unit (OU) in purchase order "
+ "management",
+ "version": "12.0.1.0.0",
"author": "Eficent, "
"Serpent Consulting Services Pvt. Ltd.,"
"Odoo Community Association (OCA)",
- "website": "http://www.eficent.com",
+ "website": "https://github.com/OCA/operating-unit",
"category": "Purchase Management",
- "depends": ["purchase", "procurement_operating_unit"],
+ "depends": ["stock_operating_unit", "purchase_stock"],
"license": "LGPL-3",
"data": [
"security/purchase_security.xml",
diff --git a/purchase_operating_unit/demo/purchase_order_demo.xml b/purchase_operating_unit/demo/purchase_order_demo.xml
index 1db5f80a9f..7071a0fba2 100644
--- a/purchase_operating_unit/demo/purchase_order_demo.xml
+++ b/purchase_operating_unit/demo/purchase_order_demo.xml
@@ -1,4 +1,8 @@
+
+
+
+
diff --git a/purchase_operating_unit/models/__init__.py b/purchase_operating_unit/models/__init__.py
index df20d9dbe3..14eb8bcd10 100644
--- a/purchase_operating_unit/models/__init__.py
+++ b/purchase_operating_unit/models/__init__.py
@@ -1,8 +1,3 @@
-# -*- coding: utf-8 -*-
-# © 2015-17 Eficent Business and IT Consulting Services S.L.
-# - Jordi Ballester Alomar
-# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-from . import purchase
-from . import procurement
-from . import invoice
+from . import purchase_order
+from . import account_invoice
diff --git a/purchase_operating_unit/models/invoice.py b/purchase_operating_unit/models/account_invoice.py
similarity index 66%
rename from purchase_operating_unit/models/invoice.py
rename to purchase_operating_unit/models/account_invoice.py
index 3505850814..93e559ec79 100644
--- a/purchase_operating_unit/models/invoice.py
+++ b/purchase_operating_unit/models/account_invoice.py
@@ -1,9 +1,8 @@
-# -*- coding: utf-8 -*-
# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-from odoo import api, models
+from odoo import _, api, exceptions, models
class AccountInvoice(models.Model):
@@ -30,3 +29,17 @@ def _onchange_allowed_purchase_ids(self):
result['domain']['purchase_id'] += [('operating_unit_id', '=',
self.operating_unit_id.id)]
return result
+
+
+class AccountInvoiceLines(models.Model):
+ _inherit = 'account.invoice.line'
+
+ @api.constrains('operating_unit_id', 'purchase_line_id')
+ def _check_invoice_ou(self):
+ for line in self:
+ if (line.purchase_line_id and line.operating_unit_id !=
+ line.purchase_line_id.operating_unit_id):
+ raise exceptions.ValidationError(
+ _('The operating unit of the purchase order must '
+ 'be the same as in the associated invoices.')
+ )
diff --git a/purchase_operating_unit/models/procurement.py b/purchase_operating_unit/models/procurement.py
deleted file mode 100644
index 2cd8e730d8..0000000000
--- a/purchase_operating_unit/models/procurement.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- coding: utf-8 -*-
-# © 2015-17 Eficent Business and IT Consulting Services S.L.
-# - Jordi Ballester Alomar
-# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
-# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-from odoo import _, api, models
-from odoo.exceptions import ValidationError
-
-
-class ProcurementOrder(models.Model):
- _inherit = 'procurement.order'
-
- @api.multi
- @api.constrains('purchase_line_id', 'location_id')
- def _check_purchase_order_operating_unit(self):
- for proc in self:
- if not proc.purchase_line_id:
- continue
- ou = proc.location_id.operating_unit_id
- order_ou = proc.purchase_line_id.operating_unit_id
- if (ou != order_ou and
- proc.location_id.usage not in ('supplier', 'customer')):
- raise ValidationError(
- _('Configuration error. The Quotation / Purchase Order '
- 'and the Procurement Order must belong to the same '
- 'Operating Unit.')
- )
-
- @api.multi
- def _prepare_purchase_order(self, partner):
- res = super(ProcurementOrder, self)._prepare_purchase_order(partner)
- operating_unit = self.location_id.operating_unit_id
- if operating_unit:
- res.update({
- 'operating_unit_id': operating_unit.id,
- 'requesting_operating_unit_id': operating_unit.id
- })
- return res
diff --git a/purchase_operating_unit/models/purchase.py b/purchase_operating_unit/models/purchase_order.py
similarity index 81%
rename from purchase_operating_unit/models/purchase.py
rename to purchase_operating_unit/models/purchase_order.py
index b7f9a01933..4149c7921f 100644
--- a/purchase_operating_unit/models/purchase.py
+++ b/purchase_operating_unit/models/purchase_order.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
@@ -69,19 +68,18 @@ def _check_warehouse_operating_unit(self):
record.operating_unit_id and
warehouse.operating_unit_id != record.operating_unit_id):
raise ValidationError(
- _('Configuration error\nThe Quotation / Purchase Order '
+ _('Configuration error. The Quotation / Purchase Order '
'and the Warehouse of picking type must belong to the '
'same Operating Unit.')
)
- @api.constrains('operating_unit_id', 'requesting_operating_unit_id',
- 'company_id')
+ @api.constrains('operating_unit_id', 'company_id')
def _check_company_operating_unit(self):
for record in self:
if (record.company_id and record.operating_unit_id and
record.company_id != record.operating_unit_id.company_id):
raise ValidationError(
- _('Configuration error\nThe Company in the Purchase Order '
+ _('Configuration error. The Company in the Purchase Order '
'and in the Operating Unit must be the same.')
)
@@ -111,16 +109,4 @@ class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
operating_unit_id = fields.Many2one(related='order_id.operating_unit_id',
- string='Operating Unit', readonly=True)
-
- @api.constrains('order_id.operating_unit_id', 'invoice_lines')
- def _check_invoice_ou(self):
- for line in self:
- for inv_line in line.invoice_lines:
- invoice_operating_unit = inv_line.invoice_id.operating_unit_id
- if (inv_line.invoice_id and
- invoice_operating_unit != line.operating_unit_id):
- raise ValidationError(
- _('The operating unit of the purchase order must '
- 'be the same as in the associated invoices.')
- )
+ string='Operating Unit')
diff --git a/purchase_operating_unit/readme/CONTRIBUTORS.rst b/purchase_operating_unit/readme/CONTRIBUTORS.rst
new file mode 100644
index 0000000000..4244f4e535
--- /dev/null
+++ b/purchase_operating_unit/readme/CONTRIBUTORS.rst
@@ -0,0 +1,3 @@
+* Jordi Ballester Alomar
+* Aaron Henriquez
+* Sudhir Arya
diff --git a/purchase_operating_unit/readme/DESCRIPTION.rst b/purchase_operating_unit/readme/DESCRIPTION.rst
new file mode 100644
index 0000000000..ace6b56436
--- /dev/null
+++ b/purchase_operating_unit/readme/DESCRIPTION.rst
@@ -0,0 +1,6 @@
+This module introduces the following features:
+
+- It introduces the operating unit to the purchase order.
+- The operating unit is copied to the invoice.
+- The operating unit is copied to the stock picking.
+- It implements user's security rules.
diff --git a/purchase_operating_unit/readme/ROADMAP.rst b/purchase_operating_unit/readme/ROADMAP.rst
new file mode 100644
index 0000000000..e066763c22
--- /dev/null
+++ b/purchase_operating_unit/readme/ROADMAP.rst
@@ -0,0 +1,3 @@
+Procurement Orders were removed. Procurement Operating Unit module is
+deprecated. Stock Operating Unit ensures consistency between the operating unit
+from different models.
diff --git a/purchase_operating_unit/readme/USAGE.rst b/purchase_operating_unit/readme/USAGE.rst
new file mode 100644
index 0000000000..0f2c129360
--- /dev/null
+++ b/purchase_operating_unit/readme/USAGE.rst
@@ -0,0 +1,6 @@
+#. Create a PO: the Default Operating Unit is assigned to the PO. If you want,
+ you can change to another Operating Unit.
+#. Validate the PO: the Operating Unit is propagated to the Pickings and
+ Invoices.
+#. From the invoice, it is not possible to change the Operating Unit, it has to
+ be the same as the one of the PO.
diff --git a/purchase_operating_unit/security/purchase_security.xml b/purchase_operating_unit/security/purchase_security.xml
index f5ed96aaee..b6727e68b9 100644
--- a/purchase_operating_unit/security/purchase_security.xml
+++ b/purchase_operating_unit/security/purchase_security.xml
@@ -1,9 +1,13 @@
+
+
+
+
- ['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]
+ ['|',('operating_unit_id','=',False),('operating_unit_id','in', user.operating_unit_ids.ids)]
PO's from allowed operating units
@@ -14,7 +18,7 @@
- ['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]
+ ['|',('operating_unit_id','=',False),('operating_unit_id','in', user.operating_unit_ids.ids)]
PO lines from allowed operating units
diff --git a/purchase_operating_unit/static/description/index.html b/purchase_operating_unit/static/description/index.html
new file mode 100644
index 0000000000..407c8c8520
--- /dev/null
+++ b/purchase_operating_unit/static/description/index.html
@@ -0,0 +1,447 @@
+
+
+
+
+
+
+Operating Unit in Purchase Orders
+
+
+
+
+
Operating Unit in Purchase Orders
+
+
+

+
This module introduces the following features:
+
+- It introduces the operating unit to the purchase order.
+- The operating unit is copied to the invoice.
+- The operating unit is copied to the stock picking.
+- It implements user’s security rules.
+
+
Table of contents
+
+
+
+
+- Create a PO: the Default Operating Unit is assigned to the PO. If you want,
+you can change to another Operating Unit.
+- Validate the PO: the Operating Unit is propagated to the Pickings and
+Invoices.
+- From the invoice, it is not possible to change the Operating Unit, it has to
+be the same as the one of the PO.
+
+
+
+
+
Procurement Orders were removed. Procurement Operating Unit module is
+deprecated. Stock Operating Unit ensures consistency between the operating unit
+from different models.
+
+
+
+
Bugs are tracked on GitHub 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.
+
Do not contact contributors directly about support or help with technical issues.
+
+
+
+
+
+
+- Eficent
+- Serpent Consulting Services Pvt. Ltd.
+
+
+
+
+
+
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.
+
This module is part of the OCA/operating-unit project on GitHub.
+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
+
+
+
+
+
diff --git a/purchase_operating_unit/tests/__init__.py b/purchase_operating_unit/tests/__init__.py
index de41426d68..9c86acd517 100644
--- a/purchase_operating_unit/tests/__init__.py
+++ b/purchase_operating_unit/tests/__init__.py
@@ -1,7 +1,3 @@
-# -*- coding: utf-8 -*-
-# © 2015-17 Eficent Business and IT Consulting Services S.L.
-# - Jordi Ballester Alomar
-# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import test_purchase_operating_unit
from . import test_po_security
diff --git a/purchase_operating_unit/tests/test_po_security.py b/purchase_operating_unit/tests/test_po_security.py
index 89d0da8ea9..04387f73a3 100644
--- a/purchase_operating_unit/tests/test_po_security.py
+++ b/purchase_operating_unit/tests/test_po_security.py
@@ -1,10 +1,8 @@
-# -*- coding: utf-8 -*-
# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-from odoo.addons.purchase_operating_unit.tests import\
- test_purchase_operating_unit as test_po_ou # noqa
+from . import test_purchase_operating_unit as test_po_ou # noqa
class TestPoSecurity(test_po_ou.TestPurchaseOperatingUnit):
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
index 63e4198f54..561a51ebd7 100644
--- a/purchase_operating_unit/tests/test_purchase_operating_unit.py
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -1,19 +1,20 @@
-# -*- coding: utf-8 -*-
# © 2015-17 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
import time
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
-from odoo.addons.purchase.tests import test_purchase_order
+from odoo.tests import common
-class TestPurchaseOperatingUnit(test_purchase_order.TestPurchaseOrder):
+class TestPurchaseOperatingUnit(common.TransactionCase):
def setUp(self):
super(TestPurchaseOperatingUnit, self).setUp()
self.ResUsers = self.env['res.users']
self.StockPicking = self.env['stock.picking']
+ self.PurchaseOrder = self.env['purchase.order']
+ self.AccountInvoice = self.env['account.invoice']
# company
self.company1 = self.env.ref('base.main_company')
self.company2 = self.env.ref('stock.res_company_1')
diff --git a/purchase_operating_unit/views/purchase_order_line_view.xml b/purchase_operating_unit/views/purchase_order_line_view.xml
index b0734875dc..11dd70fd42 100644
--- a/purchase_operating_unit/views/purchase_order_line_view.xml
+++ b/purchase_operating_unit/views/purchase_order_line_view.xml
@@ -7,7 +7,9 @@
-
+
@@ -18,7 +20,9 @@
-
+
@@ -28,12 +32,15 @@
purchase.order.line
-
-
-
+
+
+
-
+
diff --git a/purchase_operating_unit/views/purchase_order_view.xml b/purchase_operating_unit/views/purchase_order_view.xml
index a1f9b73e2b..92362e6717 100644
--- a/purchase_operating_unit/views/purchase_order_view.xml
+++ b/purchase_operating_unit/views/purchase_order_view.xml
@@ -7,7 +7,9 @@
-
+
@@ -18,13 +20,16 @@
-
-
+
+
-
+
{'operating_unit_id': operating_unit_id}
-
+
@@ -34,10 +39,14 @@
-
+
-
+
From 74e84d41feed18e3c01954214c7f99578eb189a9 Mon Sep 17 00:00:00 2001
From: oca-travis
Date: Wed, 30 Oct 2019 11:55:24 +0000
Subject: [PATCH 11/56] [UPD] Update purchase_operating_unit.pot
---
.../i18n/purchase_operating_unit.pot | 82 +++++++++++++++++++
1 file changed, 82 insertions(+)
create mode 100644 purchase_operating_unit/i18n/purchase_operating_unit.pot
diff --git a/purchase_operating_unit/i18n/purchase_operating_unit.pot b/purchase_operating_unit/i18n/purchase_operating_unit.pot
new file mode 100644
index 0000000000..1f1bb85df3
--- /dev/null
+++ b/purchase_operating_unit/i18n/purchase_operating_unit.pot
@@ -0,0 +1,82 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * purchase_operating_unit
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 12.0\n"
+"Report-Msgid-Bugs-To: \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: purchase_operating_unit
+#: code:addons/purchase_operating_unit/models/purchase_order.py:82
+#, python-format
+msgid "Configuration error. The Company in the Purchase Order and in the Operating Unit must be the same."
+msgstr ""
+
+#. module: purchase_operating_unit
+#: code:addons/purchase_operating_unit/models/purchase_order.py:71
+#, python-format
+msgid "Configuration error. The Quotation / Purchase Order and the Warehouse of picking type must belong to the same Operating Unit."
+msgstr ""
+
+#. module: purchase_operating_unit
+#: model:ir.model.fields,field_description:purchase_operating_unit.field_purchase_order__picking_type_id
+msgid "Deliver To"
+msgstr ""
+
+#. module: purchase_operating_unit
+#: model:ir.model,name:purchase_operating_unit.model_account_invoice
+msgid "Invoice"
+msgstr ""
+
+#. module: purchase_operating_unit
+#: model:ir.model,name:purchase_operating_unit.model_account_invoice_line
+msgid "Invoice Line"
+msgstr ""
+
+#. module: purchase_operating_unit
+#: code:addons/purchase_operating_unit/models/purchase_order.py:97
+#, python-format
+msgid "No Warehouse found with the Operating Unit indicated in the Purchase Order"
+msgstr ""
+
+#. module: purchase_operating_unit
+#: model:ir.model.fields,field_description:purchase_operating_unit.field_purchase_order__operating_unit_id
+#: model:ir.model.fields,field_description:purchase_operating_unit.field_purchase_order_line__operating_unit_id
+#: model_terms:ir.ui.view,arch_db:purchase_operating_unit.purchase_order_line_search
+#: model_terms:ir.ui.view,arch_db:purchase_operating_unit.view_purchase_order_filter
+msgid "Operating Unit"
+msgstr ""
+
+#. module: purchase_operating_unit
+#: model:ir.model,name:purchase_operating_unit.model_purchase_order
+msgid "Purchase Order"
+msgstr ""
+
+#. module: purchase_operating_unit
+#: model:ir.model,name:purchase_operating_unit.model_purchase_order_line
+msgid "Purchase Order Line"
+msgstr ""
+
+#. module: purchase_operating_unit
+#: model:ir.model.fields,field_description:purchase_operating_unit.field_purchase_order__requesting_operating_unit_id
+msgid "Requesting Operating Unit"
+msgstr ""
+
+#. module: purchase_operating_unit
+#: code:addons/purchase_operating_unit/models/account_invoice.py:43
+#, python-format
+msgid "The operating unit of the purchase order must be the same as in the associated invoices."
+msgstr ""
+
+#. module: purchase_operating_unit
+#: model:ir.model.fields,help:purchase_operating_unit.field_purchase_order__picking_type_id
+msgid "This will determine picking type of incoming shipment"
+msgstr ""
+
From 06f003eea13fffae5b03f78923afbbc24626605f Mon Sep 17 00:00:00 2001
From: OCA-git-bot
Date: Wed, 30 Oct 2019 12:47:36 +0000
Subject: [PATCH 12/56] [UPD] README.rst
---
purchase_operating_unit/static/description/index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/purchase_operating_unit/static/description/index.html b/purchase_operating_unit/static/description/index.html
index 407c8c8520..7457d289d2 100644
--- a/purchase_operating_unit/static/description/index.html
+++ b/purchase_operating_unit/static/description/index.html
@@ -3,7 +3,7 @@
-
+
Operating Unit in Purchase Orders
-
-
Operating Unit in Purchase Orders
+
+
+
+
+
+
-
+
- Create a PO: the Default Operating Unit is assigned to the PO. If you
want, you can change to another Operating Unit.
@@ -400,7 +405,7 @@
-
+
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
@@ -408,16 +413,16 @@
Do not contact contributors directly about support or help with technical issues.
-
+
-
+
- ForgeFlow
- Serpent Consulting Services Pvt. Ltd.
-
+
This module is maintained by the OCA.
@@ -446,5 +451,6 @@
+
From 5259cc18b5737bb19886cbf571635aca77f343f5 Mon Sep 17 00:00:00 2001
From: solomonprabu
Date: Fri, 3 Jul 2026 14:16:23 +0530
Subject: [PATCH 50/56] [IMP] purchase_operating_unit: pre-commit auto fixes
---
.gitignore | 2 ++
purchase_operating_unit/README.rst | 10 +++++-----
purchase_operating_unit/__manifest__.py | 6 +++---
purchase_operating_unit/models/account_move.py | 1 +
purchase_operating_unit/models/purchase_order.py | 1 +
purchase_operating_unit/report/purchase_report.py | 1 +
purchase_operating_unit/security/purchase_security.xml | 1 +
purchase_operating_unit/static/description/index.html | 6 +++---
purchase_operating_unit/tests/test_po_security.py | 1 +
.../tests/test_purchase_operating_unit.py | 1 +
10 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/.gitignore b/.gitignore
index 6ec07a054b..ea37c9bd87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,3 +86,5 @@ docs/_build/
# OCA rules
!static/lib/
+odoo.conf
+coverage_report.txt
diff --git a/purchase_operating_unit/README.rst b/purchase_operating_unit/README.rst
index 7f4963bd07..026d4e1b85 100644
--- a/purchase_operating_unit/README.rst
+++ b/purchase_operating_unit/README.rst
@@ -21,13 +21,13 @@ Operating Unit in Purchase Orders
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Foperating--unit-lightgray.png?logo=github
- :target: https://github.com/OCA/operating-unit/tree/18.0/purchase_operating_unit
+ :target: https://github.com/OCA/operating-unit/tree/19.0/purchase_operating_unit
:alt: OCA/operating-unit
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
- :target: https://translation.odoo-community.org/projects/operating-unit-18-0/operating-unit-18-0-purchase_operating_unit
+ :target: https://translation.odoo-community.org/projects/operating-unit-19-0/operating-unit-19-0-purchase_operating_unit
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
- :target: https://runboat.odoo-community.org/builds?repo=OCA/operating-unit&target_branch=18.0
+ :target: https://runboat.odoo-community.org/builds?repo=OCA/operating-unit&target_branch=19.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -58,7 +58,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues `_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
-`feedback `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -98,6 +98,6 @@ 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.
-This module is part of the `OCA/operating-unit `_ project on GitHub.
+This module is part of the `OCA/operating-unit `_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/purchase_operating_unit/__manifest__.py b/purchase_operating_unit/__manifest__.py
index c508707d78..ea2de5b7d1 100644
--- a/purchase_operating_unit/__manifest__.py
+++ b/purchase_operating_unit/__manifest__.py
@@ -1,13 +1,13 @@
# © 2015-17 ForgeFlow S.L.
# - Jordi Ballester Alomar
# © 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2026-27 CIT Services - Solomon Prabu
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
{
"name": "Operating Unit in Purchase Orders",
- "summary": "Adds the concecpt of operating unit (OU) in purchase order "
- "management",
- "version": "18.0.1.0.0",
+ "summary": "Adds the concecpt of operating unit (OU) in purchase order management",
+ "version": "19.0.1.0.0",
"author": "ForgeFlow, "
"Serpent Consulting Services Pvt. Ltd.,"
"Odoo Community Association (OCA)",
diff --git a/purchase_operating_unit/models/account_move.py b/purchase_operating_unit/models/account_move.py
index 77f867b301..a03ceccad2 100644
--- a/purchase_operating_unit/models/account_move.py
+++ b/purchase_operating_unit/models/account_move.py
@@ -1,6 +1,7 @@
# Copyright 2015-17 ForgeFlow S.L.
# - Jordi Ballester Alomar
# Copyright 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2026-27 CIT Services - Solomon Prabu
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, models
from odoo.exceptions import ValidationError
diff --git a/purchase_operating_unit/models/purchase_order.py b/purchase_operating_unit/models/purchase_order.py
index 215ca4727b..1c6402d06f 100644
--- a/purchase_operating_unit/models/purchase_order.py
+++ b/purchase_operating_unit/models/purchase_order.py
@@ -1,6 +1,7 @@
# Copyright 2015-17 ForgeFlow S.L.
# - Jordi Ballester Alomar
# Copyright 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2026-27 CIT Services - Solomon Prabu
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models
from odoo.exceptions import ValidationError
diff --git a/purchase_operating_unit/report/purchase_report.py b/purchase_operating_unit/report/purchase_report.py
index 994ccc82a0..6c46e88903 100644
--- a/purchase_operating_unit/report/purchase_report.py
+++ b/purchase_operating_unit/report/purchase_report.py
@@ -1,4 +1,5 @@
# Copyright 2023 Ecosoft Co., Ltd (http://ecosoft.co.th/)
+# © 2026-27 CIT Services - Solomon Prabu
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import fields, models
diff --git a/purchase_operating_unit/security/purchase_security.xml b/purchase_operating_unit/security/purchase_security.xml
index 28b1d7593e..bcc10587cb 100644
--- a/purchase_operating_unit/security/purchase_security.xml
+++ b/purchase_operating_unit/security/purchase_security.xml
@@ -1,5 +1,6 @@
+
diff --git a/purchase_operating_unit/static/description/index.html b/purchase_operating_unit/static/description/index.html
index fd0fe17c03..0b9b9e80a5 100644
--- a/purchase_operating_unit/static/description/index.html
+++ b/purchase_operating_unit/static/description/index.html
@@ -374,7 +374,7 @@ Operating Unit in Purchase Orders
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:21d7222687f368a65b0a1ac162b9e04e3a51ce6fa7cc912aff062a4bb6a7f595
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
-

+

This module introduces the following features:
- It introduces the operating unit to the purchase order.
@@ -409,7 +409,7 @@
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
-feedback.
+feedback.
Do not contact contributors directly about support or help with technical issues.
@@ -446,7 +446,7 @@
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.
-
This module is part of the OCA/operating-unit project on GitHub.
+
This module is part of the OCA/operating-unit project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/purchase_operating_unit/tests/test_po_security.py b/purchase_operating_unit/tests/test_po_security.py
index 801a5c650d..dd27ddd70a 100644
--- a/purchase_operating_unit/tests/test_po_security.py
+++ b/purchase_operating_unit/tests/test_po_security.py
@@ -1,6 +1,7 @@
# Copyright 2015-17 ForgeFlow S.L.
# - Jordi Ballester Alomar
# Copyright 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2026-27 CIT Services - Solomon Prabu
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import test_purchase_operating_unit as test_po_ou # noqa
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
index cb89f4704e..c85812ca21 100644
--- a/purchase_operating_unit/tests/test_purchase_operating_unit.py
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -1,6 +1,7 @@
# Copyright 2015-17 ForgeFlow S.L.
# - Jordi Ballester Alomar
# Copyright 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
+# © 2026-27 CIT Services - Solomon Prabu
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
import time
From 0e2516bed98bfcec1335b1886e75e9ee4ab08e95 Mon Sep 17 00:00:00 2001
From: solomonprabu
Date: Fri, 3 Jul 2026 18:17:01 +0530
Subject: [PATCH 51/56] [MIG] purchase_operating_unit: Migration to 19.0
---
.../tests/test_purchase_operating_unit.py | 8 +++-----
purchase_operating_unit/views/purchase_order_view.xml | 2 +-
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
index c85812ca21..0add003ef0 100644
--- a/purchase_operating_unit/tests/test_purchase_operating_unit.py
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -3,12 +3,10 @@
# Copyright 2015-17 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# © 2026-27 CIT Services - Solomon Prabu
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
-import time
-
+from odoo import fields
from odoo.exceptions import ValidationError
from odoo.models import Command
from odoo.tests import Form
-from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.addons.operating_unit.tests.common import OperatingUnitCommon
@@ -67,9 +65,9 @@ def _create_purchase(cls, user_id, line_products):
"qty_received_manual": qty,
"product_uom": product.uom_id.id,
"price_unit": 50,
- "date_planned": time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
+ "date_planned": fields.Datetime.now(),
}
- lines.append((0, 0, line_values))
+ lines.append(Command.create(line_values))
purchase = cls.PurchaseOrder.with_user(user_id).create(
{
"operating_unit_id": cls.ou1.id,
diff --git a/purchase_operating_unit/views/purchase_order_view.xml b/purchase_operating_unit/views/purchase_order_view.xml
index e2913ca8d8..3c5c8fdef3 100644
--- a/purchase_operating_unit/views/purchase_order_view.xml
+++ b/purchase_operating_unit/views/purchase_order_view.xml
@@ -48,7 +48,7 @@
purchase.order
-
+
Date: Mon, 6 Jul 2026 10:20:26 +0530
Subject: [PATCH 52/56] [FIX] Incorrect import fix
---
purchase_operating_unit/tests/test_purchase_operating_unit.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
index 0add003ef0..a0e1c4ed5f 100644
--- a/purchase_operating_unit/tests/test_purchase_operating_unit.py
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -5,7 +5,7 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import fields
from odoo.exceptions import ValidationError
-from odoo.models import Command
+from odoo.fields import Command
from odoo.tests import Form
from odoo.addons.operating_unit.tests.common import OperatingUnitCommon
From b668288fa83a80598536c11715c931371d1a71d5 Mon Sep 17 00:00:00 2001
From: solomonprabu
Date: Mon, 6 Jul 2026 10:29:31 +0530
Subject: [PATCH 53/56] [FIX] Product creation in tests
---
.../tests/test_purchase_operating_unit.py | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
index a0e1c4ed5f..0c5d007899 100644
--- a/purchase_operating_unit/tests/test_purchase_operating_unit.py
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -21,9 +21,15 @@ def setUpClass(cls):
# groups
cls.group_purchase_user = cls.env.ref("purchase.group_purchase_user")
# Products
- cls.product1 = cls.env.ref("product.product_product_7")
- cls.product2 = cls.env.ref("product.product_product_9")
- cls.product3 = cls.env.ref("product.product_product_11")
+ cls.product1 = cls.env["product.product"].create(
+ {"name": "Product 1", "type": "consu"}
+ )
+ cls.product2 = cls.env["product.product"].create(
+ {"name": "Product 2", "type": "consu"}
+ )
+ cls.product3 = cls.env["product.product"].create(
+ {"name": "Product 3", "type": "consu"}
+ )
(cls.product1 | cls.product2).write({"purchase_method": "purchase"})
# Account
cls.account = cls.AccountAccount.search(
From bcfd6b1f460d3af8a28a92b43a87edaee5695560 Mon Sep 17 00:00:00 2001
From: solomonprabu
Date: Mon, 6 Jul 2026 11:42:10 +0530
Subject: [PATCH 54/56] [FIX] wrong reference for groups field
---
purchase_operating_unit/tests/test_purchase_operating_unit.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
index 0c5d007899..2b15c5580a 100644
--- a/purchase_operating_unit/tests/test_purchase_operating_unit.py
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -38,14 +38,14 @@ def setUpClass(cls):
# Update users
cls.user1.write(
{
- "groups_id": [
+ "group_ids": [
Command.link(cls.group_purchase_user.id),
],
}
)
cls.user2.write(
{
- "groups_id": [
+ "group_ids": [
Command.link(cls.group_purchase_user.id),
],
"operating_unit_ids": [Command.set([cls.b2b.id])],
From e3ceda721b824363881be4f1bc2821bdfa93f610 Mon Sep 17 00:00:00 2001
From: solomonprabu
Date: Mon, 6 Jul 2026 11:48:27 +0530
Subject: [PATCH 55/56] [FIX] partner usage in tests
---
purchase_operating_unit/tests/test_purchase_operating_unit.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
index 2b15c5580a..c4833e4ac2 100644
--- a/purchase_operating_unit/tests/test_purchase_operating_unit.py
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -51,6 +51,7 @@ def setUpClass(cls):
"operating_unit_ids": [Command.set([cls.b2b.id])],
}
)
+ cls.partner1 = cls.env["res.partner"].create({"name": "Partner 1"})
cls.purchase1 = cls._create_purchase(
cls.user1,
[(cls.product1, 1000), (cls.product2, 500), (cls.product3, 800)],
From 7700f1913c11112cbbc3107607ec7564e8f7be12 Mon Sep 17 00:00:00 2001
From: solomonprabu
Date: Mon, 6 Jul 2026 12:13:58 +0530
Subject: [PATCH 56/56] [FIX] product uom wrong reference of field in tests
---
purchase_operating_unit/tests/__init__.py | 1 +
purchase_operating_unit/tests/test_purchase_operating_unit.py | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/purchase_operating_unit/tests/__init__.py b/purchase_operating_unit/tests/__init__.py
index 9c86acd517..df19e1685a 100644
--- a/purchase_operating_unit/tests/__init__.py
+++ b/purchase_operating_unit/tests/__init__.py
@@ -1,3 +1,4 @@
+# Copyright 2026-27 CIT Services - Solomon Prabu
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import test_purchase_operating_unit
from . import test_po_security
diff --git a/purchase_operating_unit/tests/test_purchase_operating_unit.py b/purchase_operating_unit/tests/test_purchase_operating_unit.py
index c4833e4ac2..74636e5d4d 100644
--- a/purchase_operating_unit/tests/test_purchase_operating_unit.py
+++ b/purchase_operating_unit/tests/test_purchase_operating_unit.py
@@ -70,7 +70,7 @@ def _create_purchase(cls, user_id, line_products):
"product_id": product.id,
"product_qty": qty,
"qty_received_manual": qty,
- "product_uom": product.uom_id.id,
+ "product_uom_id": product.uom_id.id,
"price_unit": 50,
"date_planned": fields.Datetime.now(),
}