Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
457 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
.. image:: https://img.shields.io/badge/license-LGPLv3-blue.svg | ||
:target: https://www.gnu.org/licenses/lgpl.html | ||
:alt: License: LGPL-3 | ||
|
||
=============================== | ||
Operating Unit in Sales | ||
=============================== | ||
|
||
This module was written to extend the Sales capabilities of Odoo. | ||
This module introduces the operating unit to the Sales Order. | ||
Security rules are defined to ensure that users can only display the | ||
Sales Orders in which they are allowed access to. | ||
|
||
Installation | ||
============ | ||
|
||
No additional installation instructions are required. | ||
|
||
Configuration | ||
============= | ||
|
||
Go to 'Settings / Technical / Actions / User-defined Defaults' and remove | ||
the default set for the Shop. | ||
|
||
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 | ||
<https://github.com/OCA/operating-unit/issues>`_. In case of trouble, please | ||
check there if your issue has already been reported. If you spotted it first, | ||
help us smashing it by providing a detailed and welcomed feedback. | ||
|
||
|
||
Credits | ||
======= | ||
|
||
Images | ||
------ | ||
|
||
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. | ||
|
||
Contributors | ||
------------ | ||
|
||
* Eficent <contact@eficent.com> | ||
* Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com> | ||
|
||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 models | ||
from . import report |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# -*- 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 Sales", | ||
"version": "9.0.1.0.0", | ||
"summary": "An operating unit (OU) is an organizational entity part of a " | ||
"company", | ||
"author": "Eficent Business and IT Consulting Services S.L., " | ||
"Serpent Consulting Services Pvt. Ltd.," | ||
"Odoo Community Association (OCA)", | ||
"license": "LGPL-3", | ||
"website": "http://www.eficent.com", | ||
"category": "Sales Management", | ||
"depends": ["sale", "operating_unit", "account_operating_unit"], | ||
"data": [ | ||
"views/sale_view.xml", | ||
"views/sale_report_view.xml", | ||
"security/sale_security.xml", | ||
], | ||
'installable': True | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# -*- 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 sale |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 import api, fields, models | ||
from openerp.exceptions import ValidationError | ||
from openerp.tools.translate import _ | ||
|
||
|
||
class SaleOrder(models.Model): | ||
_inherit = 'sale.order' | ||
|
||
operating_unit_id = fields.Many2one('operating.unit', 'Operating Unit', | ||
default=lambda self: | ||
self.env['res.users']. | ||
operating_unit_default_get(self._uid)) | ||
|
||
@api.multi | ||
@api.constrains('operating_unit_id', 'company_id') | ||
def _check_company_operating_unit(self): | ||
for rec in self: | ||
if rec.company_id and rec.operating_unit_id and\ | ||
rec.company_id != rec.operating_unit_id.company_id: | ||
raise ValidationError(_('Configuration error!\nThe Company in' | ||
' the Sales Order and in the Operating' | ||
' Unit must be the same.')) | ||
|
||
@api.multi | ||
def _prepare_invoice(self): | ||
self.ensure_one() | ||
invoice_vals = super(SaleOrder, self)._prepare_invoice() | ||
invoice_vals['operating_unit_id'] = self.operating_unit_id.id | ||
return invoice_vals | ||
|
||
|
||
class SaleOrderLine(models.Model): | ||
_inherit = 'sale.order.line' | ||
|
||
operating_unit_id = fields.Many2one('operating.unit', | ||
related='order_id.operating_unit_id', | ||
string='Operating Unit', | ||
readonly=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# -*- coding: utf-8 -*- | ||
# © 2016 Eficent Business and IT Consulting Services S.L. | ||
# - Jordi Ballester Alomar | ||
# © 2016 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
from . import sale_report |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2016 Eficent Business and IT Consulting Services S.L. | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0). | ||
|
||
from openerp import fields, models | ||
|
||
|
||
class SaleReport(models.Model): | ||
|
||
_inherit = "sale.report" | ||
|
||
operating_unit_id = fields.Many2one('operating.unit', 'Operating Unit') | ||
|
||
def _select(self): | ||
select_str = super(SaleReport, self)._select() | ||
select_str += """ | ||
,s.operating_unit_id | ||
""" | ||
return select_str | ||
|
||
def _group_by(self): | ||
group_by_str = super(SaleReport, self)._group_by() | ||
group_by_str += """ | ||
,s.operating_unit_id | ||
""" | ||
return group_by_str |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!-- Copyright 2015 Eficent Business and IT Consulting Services S.L. | ||
Serpent Consulting Services Pvt. Ltd. | ||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) --> | ||
<openerp> | ||
<data noupdate="0"> | ||
|
||
<record id="ir_rule_sale_order_allowed_operating_units" | ||
model="ir.rule"> | ||
<field name="model_id" ref="sale.model_sale_order"/> | ||
<field name="domain_force">['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]</field> | ||
<field name="name">Sales Orders from allowed operating units</field> | ||
<field name="global" eval="True"/> | ||
<field eval="0" name="perm_unlink"/> | ||
<field eval="0" name="perm_write"/> | ||
<field eval="1" name="perm_read"/> | ||
<field eval="0" name="perm_create"/> | ||
</record> | ||
|
||
<record id="ir_rule_sale_order_line_allowed_operating_units" | ||
model="ir.rule"> | ||
<field name="model_id" ref="sale.model_sale_order_line"/> | ||
<field name="domain_force">['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]</field> | ||
<field name="name">Sales Order lines from allowed operating units</field> | ||
<field name="global" eval="True"/> | ||
<field eval="0" name="perm_unlink"/> | ||
<field eval="0" name="perm_write"/> | ||
<field eval="1" name="perm_read"/> | ||
<field eval="0" name="perm_create"/> | ||
</record> | ||
|
||
<record id="ir_rule_sale_report_allowed_operating_units" | ||
model="ir.rule"> | ||
<field name="model_id" ref="sale.model_sale_report"/> | ||
<field name="domain_force">['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]</field> | ||
<field name="name">Sales Report from allowed operating units</field> | ||
<field name="global" eval="True"/> | ||
<field eval="0" name="perm_unlink"/> | ||
<field eval="0" name="perm_write"/> | ||
<field eval="1" name="perm_read"/> | ||
<field eval="0" name="perm_create"/> | ||
</record> | ||
|
||
</data> | ||
</openerp> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# -*- 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_sale_operating_unit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
# -*- coding: utf-8 -*- | ||
# © 2015 Eficent Business and IT Consulting Services S.L. - | ||
# Jordi Ballester Alomar | ||
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
from openerp.tests import common | ||
|
||
|
||
class TestSaleOperatingUnit(common.TransactionCase): | ||
|
||
def setUp(self): | ||
super(TestSaleOperatingUnit, self).setUp() | ||
self.res_groups = self.env['res.groups'] | ||
self.partner_model = self.env['res.partner'] | ||
self.res_users_model = self.env['res.users'] | ||
self.sale_model = self.env['sale.order'] | ||
self.sale_order_model = self.env['sale.order.line'] | ||
self.acc_move_model = self.env['account.move'] | ||
self.acc_invoice_model = self.env['account.invoice'] | ||
self.res_company_model = self.env['res.company'] | ||
self.product_model = self.env['product.product'] | ||
self.operating_unit_model = self.env['operating.unit'] | ||
self.company_model = self.env['res.company'] | ||
self.payment_model = self.env['sale.advance.payment.inv'] | ||
# Company | ||
self.company = self.env.ref('base.main_company') | ||
self.grp_sale_user = self.env.ref('base.group_sale_manager') | ||
self.grp_acc_user = self.env.ref('account.group_account_invoice') | ||
# 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') | ||
# B2C Operating Unit | ||
self.b2c = self.env.ref('operating_unit.b2c_operating_unit') | ||
# Payment Term | ||
self.pay = self.env.ref('account.account_payment_term_immediate') | ||
# Customer | ||
self.customer = self.env.ref('base.res_partner_2') | ||
# Price list | ||
self.pricelist = self.env.ref('product.list0') | ||
# Partner | ||
self.partner1 = self.env.ref('base.res_partner_1') | ||
# Products | ||
self.product1 = self.env.ref( | ||
'product.product_product_7') | ||
self.product1.write({'invoice_policy': 'order'}) | ||
# Create user1 | ||
self.user1 = self._create_user('user_1', [self.grp_sale_user, | ||
self.grp_acc_user], | ||
self.company, [self.ou1, self.b2c]) | ||
# Create user2 | ||
self.user2 = self._create_user('user_2', [self.grp_sale_user, | ||
self.grp_acc_user], | ||
self.company, [self.b2c]) | ||
# Create Sale Order1 | ||
self.sale1 = self._create_sale_order(self.user1.id, self.customer, | ||
self.product1, self.pricelist, | ||
self.ou1) | ||
# Create Sale Order2 | ||
self.sale2 = self._create_sale_order(self.user2.id, self.customer, | ||
self.product1, self.pricelist, | ||
self.b2c) | ||
|
||
def _create_user(self, login, groups, company, operating_units, | ||
context=None): | ||
"""Create a user.""" | ||
group_ids = [group.id for group in groups] | ||
user = self.res_users_model.create({ | ||
'name': 'Test Sales User', | ||
'login': login, | ||
'password': 'demo', | ||
'email': 'example@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 | ||
|
||
def _create_sale_order(self, uid, customer, product, pricelist, | ||
operating_unit): | ||
"""Create a sale order.""" | ||
sale = self.sale_model.sudo(uid).create({ | ||
'partner_id': customer.id, | ||
'partner_invoice_id': customer.id, | ||
'partner_shipping_id': customer.id, | ||
'pricelist_id': pricelist.id, | ||
'operating_unit_id': operating_unit.id | ||
}) | ||
self.sale_order_model.sudo(uid).create({ | ||
'order_id': sale.id, | ||
'product_id': product.id, | ||
'name': 'Sale Order Line' | ||
}) | ||
return sale | ||
|
||
def _confirm_sale(self, sale): | ||
sale.action_confirm() | ||
payment = self.payment_model.create({ | ||
'advance_payment_method': 'all' | ||
}) | ||
sale_context = { | ||
'active_id': sale.id, | ||
'active_ids': sale.ids, | ||
'active_model': 'sale.order', | ||
'open_invoices': True, | ||
} | ||
res = payment.with_context(sale_context).create_invoices() | ||
invoice_id = res['res_id'] | ||
return invoice_id | ||
|
||
def test_security(self): | ||
"""Test Sale Operating Unit""" | ||
# User 2 is only assigned to Operating Unit B2C, and cannot | ||
# Access Sales order from Main Operating Unit. | ||
sale = self.sale_model.sudo(self.user2.id).search( | ||
[('id', '=', self.sale1.id), | ||
('operating_unit_id', '=', self.ou1.id)]) | ||
self.assertEqual(sale.ids, [], 'User 2 should not have access to ' | ||
'OU %s' % self.ou1.name) | ||
# Confirm Sale1 | ||
self._confirm_sale(self.sale1) | ||
# Confirm Sale2 | ||
b2c_invoice_id = self._confirm_sale(self.sale2) | ||
# Checks that invoice has OU b2c | ||
b2c = self.acc_invoice_model.sudo(self.user2.id).search( | ||
[('id', '=', b2c_invoice_id), | ||
('operating_unit_id', '=', self.b2c.id)]) | ||
self.assertNotEqual(b2c.ids, [], 'Invoice should have b2c OU') | ||
|
||
def test_security_2(self): | ||
"""Test Sale Operating Unit""" | ||
# User 2 is only assigned to Operating Unit B2C, and cannot | ||
# Access Sales order from Main Operating Unit. | ||
sale = self.sale_model.sudo(self.user2.id).search( | ||
[('id', '=', self.sale1.id), | ||
('operating_unit_id', '=', | ||
self.ou1.id)]) | ||
self.assertEqual(sale.ids, [], 'User 2 should not have access to ' | ||
'OU %s' % self.ou1.name) | ||
|
||
sale = self.sale_model.sudo(self.user2.id).search( | ||
[('id', '=', self.sale2.id), | ||
('operating_unit_id', '=', | ||
self.b2c.id)]) | ||
|
||
self.assertEqual(len(sale.ids), 1, 'User 1 should have access to ' | ||
'OU %s' % self.b2c.name) |
Oops, something went wrong.