Skip to content

Commit

Permalink
Merge 3f52abb into dc2517a
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronHForgeFlow committed Sep 28, 2016
2 parents dc2517a + 3f52abb commit ca9f124
Show file tree
Hide file tree
Showing 12 changed files with 457 additions and 0 deletions.
66 changes: 66 additions & 0 deletions sale_operating_unit/README.rst
@@ -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.
7 changes: 7 additions & 0 deletions sale_operating_unit/__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 models
from . import report
24 changes: 24 additions & 0 deletions sale_operating_unit/__openerp__.py
@@ -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
}
6 changes: 6 additions & 0 deletions sale_operating_unit/models/__init__.py
@@ -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
43 changes: 43 additions & 0 deletions sale_operating_unit/models/sale.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 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)
7 changes: 7 additions & 0 deletions sale_operating_unit/report/__init__.py
@@ -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
26 changes: 26 additions & 0 deletions sale_operating_unit/report/sale_report.py
@@ -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
45 changes: 45 additions & 0 deletions sale_operating_unit/security/sale_security.xml
@@ -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>
6 changes: 6 additions & 0 deletions sale_operating_unit/tests/__init__.py
@@ -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
148 changes: 148 additions & 0 deletions sale_operating_unit/tests/test_sale_operating_unit.py
@@ -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)

0 comments on commit ca9f124

Please sign in to comment.