Browse Source

[IMP] date_range: adapt to multicompany

pull/25/head
mreficent 7 years ago
committed by Pedro M. Baeza
parent
commit
d4fa1102b3
  1. 1
      date_range/README.rst
  2. 2
      date_range/__manifest__.py
  3. 9
      date_range/migrations/11.0.2.0.0/noupdate_changes.xml
  4. 3
      date_range/migrations/11.0.2.0.0/openupgrade_analysis.txt
  5. 4
      date_range/migrations/11.0.2.0.0/openupgrade_analysis_work.txt
  6. 11
      date_range/migrations/11.0.2.0.0/post-migration.py
  7. 20
      date_range/models/date_range.py
  8. 17
      date_range/models/date_range_type.py
  9. 4
      date_range/security/date_range_security.xml
  10. 63
      date_range/tests/test_date_range.py
  11. 44
      date_range/tests/test_date_range_generator.py
  12. 31
      date_range/tests/test_date_range_type.py
  13. 22
      date_range/wizard/date_range_generator.py

1
date_range/README.rst

@ -91,6 +91,7 @@ Contributors
------------ ------------
* Laurent Mignon <laurent.mignon@acsone.eu> * Laurent Mignon <laurent.mignon@acsone.eu>
* Miquel Raïch <miquel.raich@eficent.com>
Maintainer Maintainer
---------- ----------

2
date_range/__manifest__.py

@ -3,7 +3,7 @@
{ {
"name": "Date Range", "name": "Date Range",
"summary": "Manage all kind of date range", "summary": "Manage all kind of date range",
"version": "11.0.1.0.1",
"version": "11.0.2.0.0",
"category": "Uncategorized", "category": "Uncategorized",
"website": "https://github.com/oca/server-ux", "website": "https://github.com/oca/server-ux",
"author": "ACSONE SA/NV, Odoo Community Association (OCA)", "author": "ACSONE SA/NV, Odoo Community Association (OCA)",

9
date_range/migrations/11.0.2.0.0/noupdate_changes.xml

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<odoo>
<record id="date_range_type_comp_rule" model="ir.rule">
<field name="domain_force"> ['|',('company_id','child_of',[user.company_id.id]),('company_id','=',False)]</field>
</record>
<record id="date_range_comp_rule" model="ir.rule">
<field name="domain_force"> ['|',('company_id','child_of',[user.company_id.id]),('company_id','=',False)]</field>
</record>
</odoo>

3
date_range/migrations/11.0.2.0.0/openupgrade_analysis.txt

@ -0,0 +1,3 @@
---Fields in module 'date_range'---
---XML records in module 'date_range'---
NEW ir.rule: date_range.date_range_generator_comp_rule (noupdate)

4
date_range/migrations/11.0.2.0.0/openupgrade_analysis_work.txt

@ -0,0 +1,4 @@
---Fields in module 'date_range'---
---XML records in module 'date_range'---
NEW ir.rule: date_range.date_range_generator_comp_rule (noupdate)
# NOTHING TO DO

11
date_range/migrations/11.0.2.0.0/post-migration.py

@ -0,0 +1,11 @@
# Copyright 2017 Eficent <http://www.eficent.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openupgradelib import openupgrade
@openupgrade.migrate()
def migrate(env, version):
openupgrade.load_data(
env.cr, 'date_range', 'migrations/11.0.2.0.0/noupdate_changes.xml',
)

20
date_range/models/date_range.py

@ -19,7 +19,8 @@ class DateRange(models.Model):
date_end = fields.Date(string='End date', required=True) date_end = fields.Date(string='End date', required=True)
type_id = fields.Many2one( type_id = fields.Many2one(
comodel_name='date.range.type', string='Type', index=1, required=True, comodel_name='date.range.type', string='Type', index=1, required=True,
ondelete='restrict')
ondelete='restrict', domain="['|', ('company_id', '=', company_id), "
"('company_id', '=', False)]")
type_name = fields.Char( type_name = fields.Char(
string='Type', related='type_id.name', readonly=True, store=True) string='Type', related='type_id.name', readonly=True, store=True)
company_id = fields.Many2one( company_id = fields.Many2one(
@ -33,6 +34,23 @@ class DateRange(models.Model):
('date_range_uniq', 'unique (name,type_id, company_id)', ('date_range_uniq', 'unique (name,type_id, company_id)',
'A date range must be unique per company !')] 'A date range must be unique per company !')]
@api.onchange('company_id')
def _onchange_company_id(self):
if self.company_id and self.type_id.company_id and \
self.type_id.company_id != self.company_id:
self._cache.update(
self._convert_to_cache({'type_id': False}, update=True))
@api.multi
@api.constrains('company_id', 'type_id')
def _check_company_id_type_id(self):
for rec in self.sudo():
if rec.company_id and rec.type_id.company_id and\
rec.company_id != rec.type_id.company_id:
raise ValidationError(
_('The Company in the Date Range and in '
'Date Range Type must be the same.'))
@api.constrains('type_id', 'date_start', 'date_end', 'company_id') @api.constrains('type_id', 'date_start', 'date_end', 'company_id')
def _validate_range(self): def _validate_range(self):
for this in self: for this in self:

17
date_range/models/date_range_type.py

@ -2,6 +2,8 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models from odoo import api, fields, models
from odoo.tools.translate import _
from odoo.exceptions import ValidationError
class DateRangeType(models.Model): class DateRangeType(models.Model):
@ -21,7 +23,22 @@ class DateRangeType(models.Model):
company_id = fields.Many2one( company_id = fields.Many2one(
comodel_name='res.company', string='Company', index=1, comodel_name='res.company', string='Company', index=1,
default=_default_company) default=_default_company)
date_range_ids = fields.One2many('date.range', 'type_id', string='Ranges')
_sql_constraints = [ _sql_constraints = [
('date_range_type_uniq', 'unique (name,company_id)', ('date_range_type_uniq', 'unique (name,company_id)',
'A date range type must be unique per company !')] 'A date range type must be unique per company !')]
@api.constrains('company_id')
def _check_company_id(self):
if not self.env.context.get('bypass_company_validation', False):
for rec in self.sudo():
if not rec.company_id:
continue
if bool(self.date_range_ids.filtered(
lambda r: r.company_id and
r.company_id != rec.company_id)):
raise ValidationError(
_('You cannot change the company, as this '
'Date Range Type is assigned to Date Range '
'(%s).') % (self.date_range_ids.name_get()[0][1]))

4
date_range/security/date_range_security.xml

@ -3,11 +3,11 @@
<record id="date_range_type_comp_rule" model="ir.rule"> <record id="date_range_type_comp_rule" model="ir.rule">
<field name="name">Date Range Type multi-company</field> <field name="name">Date Range Type multi-company</field>
<field name="model_id" ref="model_date_range_type"/> <field name="model_id" ref="model_date_range_type"/>
<field name="domain_force"> ['|',('company_id','=',user.company_id.id),('company_id','=',False)]</field>
<field name="domain_force"> ['|',('company_id','child_of',[user.company_id.id]),('company_id','=',False)]</field>
</record> </record>
<record id="date_range_comp_rule" model="ir.rule"> <record id="date_range_comp_rule" model="ir.rule">
<field name="name">Date Range multi-company</field> <field name="name">Date Range multi-company</field>
<field name="model_id" ref="model_date_range"/> <field name="model_id" ref="model_date_range"/>
<field name="domain_force"> ['|',('company_id','=',user.company_id.id),('company_id','=',False)]</field>
<field name="domain_force"> ['|',('company_id','child_of',[user.company_id.id]),('company_id','=',False)]</field>
</record> </record>
</odoo> </odoo>

63
date_range/tests/test_date_range.py

@ -9,45 +9,55 @@ class DateRangeTest(TransactionCase):
def setUp(self): def setUp(self):
super(DateRangeTest, self).setUp() super(DateRangeTest, self).setUp()
self.date_range = self.env['date.range']
self.type = self.env['date.range.type'].create( self.type = self.env['date.range.type'].create(
{'name': 'Fiscal year', {'name': 'Fiscal year',
'company_id': False, 'company_id': False,
'allow_overlap': False}) 'allow_overlap': False})
self.company = self.env['res.company'].create({
'name': 'Test company',
})
self.company_2 = self.env['res.company'].create({
'name': 'Test company 2',
'parent_id': self.company.id,
})
self.typeB = self.env['date.range.type'].create(
{'name': 'Fiscal year B',
'company_id': self.company.id,
'allow_overlap': False})
def test_default_company(self): def test_default_company(self):
date_range = self.env['date.range']
dt = date_range.create({
dr = self.date_range.create({
'name': 'FS2016', 'name': 'FS2016',
'date_start': '2015-01-01', 'date_start': '2015-01-01',
'date_end': '2016-12-31', 'date_end': '2016-12-31',
'type_id': self.type.id, 'type_id': self.type.id,
}) })
self.assertTrue(dt.company_id)
self.assertTrue(dr.company_id)
# you can specify company_id to False # you can specify company_id to False
dt = date_range.create({
dr = self.date_range.create({
'name': 'FS2016_NO_COMPANY', 'name': 'FS2016_NO_COMPANY',
'date_start': '2015-01-01', 'date_start': '2015-01-01',
'date_end': '2016-12-31', 'date_end': '2016-12-31',
'type_id': self.type.id, 'type_id': self.type.id,
'company_id': False 'company_id': False
}) })
self.assertFalse(dt.company_id)
self.assertFalse(dr.company_id)
def test_empty_company(self): def test_empty_company(self):
date_range = self.env['date.range']
dt = date_range.create({
dr = self.date_range.create({
'name': 'FS2016', 'name': 'FS2016',
'date_start': '2015-01-01', 'date_start': '2015-01-01',
'date_end': '2016-12-31', 'date_end': '2016-12-31',
'type_id': self.type.id, 'type_id': self.type.id,
'company_id': None, 'company_id': None,
}) })
self.assertEqual(dt.name, 'FS2016')
self.assertEqual(dr.name, 'FS2016')
def test_invalid(self): def test_invalid(self):
date_range = self.env['date.range']
with self.assertRaises(ValidationError) as cm: with self.assertRaises(ValidationError) as cm:
date_range.create({
self.date_range.create({
'name': 'FS2016', 'name': 'FS2016',
'date_end': '2015-01-01', 'date_end': '2015-01-01',
'date_start': '2016-12-31', 'date_start': '2016-12-31',
@ -58,15 +68,14 @@ class DateRangeTest(TransactionCase):
'FS2016 is not a valid range (2016-12-31 > 2015-01-01)') 'FS2016 is not a valid range (2016-12-31 > 2015-01-01)')
def test_overlap(self): def test_overlap(self):
date_range = self.env['date.range']
date_range.create({
self.date_range.create({
'name': 'FS2015', 'name': 'FS2015',
'date_start': '2015-01-01', 'date_start': '2015-01-01',
'date_end': '2015-12-31', 'date_end': '2015-12-31',
'type_id': self.type.id, 'type_id': self.type.id,
}) })
with self.assertRaises(ValidationError) as cm, self.env.cr.savepoint(): with self.assertRaises(ValidationError) as cm, self.env.cr.savepoint():
date_range.create({
self.date_range.create({
'name': 'FS2016', 'name': 'FS2016',
'date_start': '2015-01-01', 'date_start': '2015-01-01',
'date_end': '2016-12-31', 'date_end': '2016-12-31',
@ -75,7 +84,7 @@ class DateRangeTest(TransactionCase):
self.assertEqual(cm.exception.name, 'FS2016 overlaps FS2015') self.assertEqual(cm.exception.name, 'FS2016 overlaps FS2015')
# check it's possible to overlap if it's allowed by the date range type # check it's possible to overlap if it's allowed by the date range type
self.type.allow_overlap = True self.type.allow_overlap = True
dr = date_range.create({
dr = self.date_range.create({
'name': 'FS2016', 'name': 'FS2016',
'date_start': '2015-01-01', 'date_start': '2015-01-01',
'date_end': '2016-12-31', 'date_end': '2016-12-31',
@ -84,8 +93,7 @@ class DateRangeTest(TransactionCase):
self.assertEqual(dr.name, 'FS2016') self.assertEqual(dr.name, 'FS2016')
def test_domain(self): def test_domain(self):
date_range = self.env['date.range']
dr = date_range.create({
dr = self.date_range.create({
'name': 'FS2015', 'name': 'FS2015',
'date_start': '2015-01-01', 'date_start': '2015-01-01',
'date_end': '2015-12-31', 'date_end': '2015-12-31',
@ -97,3 +105,26 @@ class DateRangeTest(TransactionCase):
domain, domain,
[('my_field', '>=', '2015-01-01'), [('my_field', '>=', '2015-01-01'),
('my_field', '<=', '2015-12-31')]) ('my_field', '<=', '2015-12-31')])
def test_date_range_multicompany_1(self):
dr = self.date_range.new({
'name': 'FS2016',
'date_start': '2015-01-01',
'date_end': '2016-12-31',
'type_id': self.typeB.id,
'company_id': self.company.id,
})
dr._cache.update(dr._convert_to_cache(
{'company_id': self.company_2.id}, update=True))
dr._onchange_company_id()
self.assertFalse(dr.type_id)
def test_date_range_multicompany_2(self):
with self.assertRaises(ValidationError):
self.date_range.create({
'name': 'FS2016',
'date_start': '2015-01-01',
'date_end': '2016-12-31',
'type_id': self.typeB.id,
'company_id': self.company_2.id,
})

44
date_range/tests/test_date_range_generator.py

@ -2,6 +2,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)nses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)nses/agpl).
from odoo.tests.common import TransactionCase from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError
from dateutil.rrule import MONTHLY from dateutil.rrule import MONTHLY
@ -9,14 +10,26 @@ class DateRangeGeneratorTest(TransactionCase):
def setUp(self): def setUp(self):
super(DateRangeGeneratorTest, self).setUp() super(DateRangeGeneratorTest, self).setUp()
self.generator = self.env['date.range.generator']
self.type = self.env['date.range.type'].create( self.type = self.env['date.range.type'].create(
{'name': 'Fiscal year', {'name': 'Fiscal year',
'company_id': False, 'company_id': False,
'allow_overlap': False}) 'allow_overlap': False})
self.company = self.env['res.company'].create({
'name': 'Test company',
})
self.company_2 = self.env['res.company'].create({
'name': 'Test company 2',
'parent_id': self.company.id,
})
self.typeB = self.env['date.range.type'].create(
{'name': 'Fiscal year B',
'company_id': self.company.id,
'allow_overlap': False})
def test_generate(self): def test_generate(self):
generator = self.env['date.range.generator']
generator = generator.create({
generator = self.generator.create({
'date_start': '1943-01-01', 'date_start': '1943-01-01',
'name_prefix': '1943-', 'name_prefix': '1943-',
'type_id': self.type.id, 'type_id': self.type.id,
@ -31,3 +44,30 @@ class DateRangeGeneratorTest(TransactionCase):
self.assertEqual(range4.date_start, '1943-10-01') self.assertEqual(range4.date_start, '1943-10-01')
self.assertEqual(range4.date_end, '1943-12-31') self.assertEqual(range4.date_end, '1943-12-31')
self.assertEqual(range4.type_id, self.type) self.assertEqual(range4.type_id, self.type)
def test_generator_multicompany_1(self):
generator = self.generator.new({
'date_start': '1943-01-01',
'name_prefix': '1943-',
'type_id': self.typeB.id,
'duration_count': 3,
'unit_of_time': MONTHLY,
'count': 4,
'company_id': self.company.id,
})
generator._cache.update(generator._convert_to_cache(
{'company_id': self.company_2.id}, update=True))
generator._onchange_company_id()
self.assertFalse(generator.type_id)
def test_generator_multicompany_2(self):
with self.assertRaises(ValidationError):
self.generator.create({
'date_start': '1943-01-01',
'name_prefix': '1943-',
'type_id': self.typeB.id,
'duration_count': 3,
'unit_of_time': MONTHLY,
'count': 4,
'company_id': self.company_2.id,
})

31
date_range/tests/test_date_range_type.py

@ -4,17 +4,29 @@
from odoo.tests.common import TransactionCase from odoo.tests.common import TransactionCase
from odoo.tools import mute_logger from odoo.tools import mute_logger
from psycopg2 import IntegrityError from psycopg2 import IntegrityError
from odoo.exceptions import ValidationError
class DateRangeTypeTest(TransactionCase): class DateRangeTypeTest(TransactionCase):
def setUp(self):
super(DateRangeTypeTest, self).setUp()
self.type = self.env['date.range.type']
self.company = self.env['res.company'].create({
'name': 'Test company',
})
self.company_2 = self.env['res.company'].create({
'name': 'Test company 2',
'parent_id': self.company.id,
})
def test_default_company(self): def test_default_company(self):
drt = self.env['date.range.type'].create(
drt = self.type.create(
{'name': 'Fiscal year', {'name': 'Fiscal year',
'allow_overlap': False}) 'allow_overlap': False})
self.assertTrue(drt.company_id) self.assertTrue(drt.company_id)
# you can specify company_id to False # you can specify company_id to False
drt = self.env['date.range.type'].create(
drt = self.type.create(
{'name': 'Fiscal year', {'name': 'Fiscal year',
'company_id': False, 'company_id': False,
'allow_overlap': False}) 'allow_overlap': False})
@ -33,3 +45,18 @@ class DateRangeTypeTest(TransactionCase):
}) })
with self.assertRaises(IntegrityError), mute_logger('odoo.sql_db'): with self.assertRaises(IntegrityError), mute_logger('odoo.sql_db'):
drt.unlink() drt.unlink()
def test_type_multicompany(self):
drt = self.type.create(
{'name': 'Fiscal year',
'company_id': False,
'allow_overlap': False})
self.env['date.range'].create({
'name': 'FS2016',
'date_start': '2015-01-01',
'date_end': '2016-12-31',
'type_id': drt.id,
'company_id': self.company.id,
})
with self.assertRaises(ValidationError):
drt.company_id = self.company_2

22
date_range/wizard/date_range_generator.py

@ -2,6 +2,8 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models from odoo import api, fields, models
from odoo.tools.translate import _
from odoo.exceptions import ValidationError
from dateutil.rrule import (rrule, from dateutil.rrule import (rrule,
YEARLY, YEARLY,
MONTHLY, MONTHLY,
@ -21,7 +23,8 @@ class DateRangeGenerator(models.TransientModel):
date_start = fields.Date(strint='Start date', required=True) date_start = fields.Date(strint='Start date', required=True)
type_id = fields.Many2one( type_id = fields.Many2one(
comodel_name='date.range.type', string='Type', required=True, comodel_name='date.range.type', string='Type', required=True,
ondelete='cascade')
domain="['|', ('company_id', '=', company_id), "
"('company_id', '=', False)]", ondelete='cascade')
company_id = fields.Many2one( company_id = fields.Many2one(
comodel_name='res.company', string='Company', comodel_name='res.company', string='Company',
default=_default_company) default=_default_company)
@ -58,6 +61,23 @@ class DateRangeGenerator(models.TransientModel):
'company_id': self.company_id.id}) 'company_id': self.company_id.id})
return date_ranges return date_ranges
@api.onchange('company_id')
def _onchange_company_id(self):
if self.company_id and self.type_id.company_id and \
self.type_id.company_id != self.company_id:
self._cache.update(
self._convert_to_cache({'type_id': False}, update=True))
@api.multi
@api.constrains('company_id', 'type_id')
def _check_company_id_type_id(self):
for rec in self.sudo():
if rec.company_id and rec.type_id.company_id and\
rec.company_id != rec.type_id.company_id:
raise ValidationError(
_('The Company in the Date Range Generator and in '
'Date Range Type must be the same.'))
@api.multi @api.multi
def action_apply(self): def action_apply(self):
date_ranges = self._compute_date_ranges() date_ranges = self._compute_date_ranges()

Loading…
Cancel
Save