diff --git a/CHANGELOG b/CHANGELOG index 7d633f7113..86ff3ccb14 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add deletable and writable state from ir.rule to read * Add language attribute to data tag * Add e-mail template * Send e-mail on behalf of user diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py index 5c04ca9ea9..06a4dcead1 100644 --- a/trytond/model/modelsql.py +++ b/trytond/model/modelsql.py @@ -696,7 +696,7 @@ class ModelSQL(ModelStorage): if 'write_date' not in fields_names: extra_fields.add('write_date') for field_name in fields_names: - if field_name == '_timestamp': + if field_name in {'_timestamp', '_write', '_delete'}: continue if '.' in field_name: field_name, field_related = field_name.split('.', 1) @@ -732,6 +732,26 @@ class ModelSQL(ModelStorage): field = cls._fields.get(f) if field and field.sql_type(): columns.append(field.sql_column(table).as_(f)) + elif f in {'_write', '_delete'}: + if not callable(cls.table_query): + rule_domain = Rule.domain_get( + cls.__name__, mode=f.lstrip('_')) + if rule_domain: + rule_tables = {None: (table, None)} + rule_tables, rule_expression = cls.search_domain( + rule_domain, tables=rule_tables) + if len(rule_tables) > 1: + # The expression uses another table + rule_tables, rule_expression = cls.search_domain( + rule_domain) + rule_from = convert_from(None, rule_tables) + rule_table, _ = rule_tables[None] + rule_where = rule_table.id == table.id + rule_expression = rule_from.select( + rule_expression, where=rule_where) + columns.append(rule_expression.as_(f)) + else: + columns.append(Literal(True).as_(f)) elif f == '_timestamp' and not callable(cls.table_query): sql_type = fields.Char('timestamp').sql_type().base columns.append(Extract('EPOCH', @@ -774,7 +794,7 @@ class ModelSQL(ModelStorage): for column in columns: # Split the output name to remove SQLite type detection fname = column.output_name.split()[0] - if fname == '_timestamp': + if fname.startswith('_'): continue field = cls._fields[fname] if not hasattr(field, 'get'): diff --git a/trytond/tests/rule.py b/trytond/tests/rule.py index 32ff686b5e..9c9cdff7b1 100644 --- a/trytond/tests/rule.py +++ b/trytond/tests/rule.py @@ -8,9 +8,17 @@ class TestRule(ModelSQL): "Test Rule" __name__ = 'test.rule' field = fields.Char("Field") + relation = fields.Many2One('test.rule.relation', "Relation") + + +class TestRuleRelation(ModelSQL): + "Test Rule Relation" + __name__ = 'test.rule.relation' + field = fields.Char("Field") def register(module): Pool.register( TestRule, + TestRuleRelation, module=module, type_='model') diff --git a/trytond/tests/test_rule.py b/trytond/tests/test_rule.py index fcd525f590..fcd7adfbee 100644 --- a/trytond/tests/test_rule.py +++ b/trytond/tests/test_rule.py @@ -379,6 +379,250 @@ class ModelRuleTestCase(unittest.TestCase): self.assertListEqual(TestRule.search([]), []) + @with_transaction() + def test_write_field_no_rule(self): + "Test _write field when there's no rule" + pool = Pool() + TestRule = pool.get('test.rule') + writable, = TestRule.create([{'field': 'foo'}]) + + value, = TestRule.read([writable.id], ['_write']) + self.assertEqual(value['_write'], True) + + @with_transaction() + def test_write_field_rule_True(self): + "Test _write field when there's a rule - True" + pool = Pool() + TestRule = pool.get('test.rule') + RuleGroup = pool.get('ir.rule.group') + Model = pool.get('ir.model') + + model, = Model.search([('model', '=', 'test.rule')]) + rule_group, = RuleGroup.create([{ + 'name': "Field different from foo", + 'model': model.id, + 'global_p': True, + 'perm_read': False, + 'perm_create': False, + 'perm_write': True, + 'perm_delete': False, + 'rules': [('create', [{ + 'domain': json.dumps( + [('field', '!=', 'foo')]), + }])], + }]) + writable, = TestRule.create([{'field': 'bar'}]) + + value, = TestRule.read([writable.id], ['_write']) + self.assertEqual(value['_write'], True) + + @with_transaction() + def test_write_field_rule_False(self): + "Test _write field when there's a rule - False" + pool = Pool() + TestRule = pool.get('test.rule') + RuleGroup = pool.get('ir.rule.group') + Model = pool.get('ir.model') + + model, = Model.search([('model', '=', 'test.rule')]) + rule_group, = RuleGroup.create([{ + 'name': "Field different from foo", + 'model': model.id, + 'global_p': True, + 'perm_read': False, + 'perm_create': False, + 'perm_write': True, + 'perm_delete': False, + 'rules': [('create', [{ + 'domain': json.dumps( + [('field', '!=', 'foo')]), + }])], + }]) + non_writable, = TestRule.create([{'field': 'foo'}]) + + value, = TestRule.read([non_writable.id], ['_write']) + self.assertEqual(value['_write'], False) + + @with_transaction() + def test_write_field_relation_rule_True(self): + "Test _write field when there's a rule with a relation - True" + pool = Pool() + TestRule = pool.get('test.rule') + TestRuleRelation = pool.get('test.rule.relation') + RuleGroup = pool.get('ir.rule.group') + Model = pool.get('ir.model') + + model, = Model.search([('model', '=', 'test.rule')]) + rule_group, = RuleGroup.create([{ + 'name': "Field different from foo", + 'model': model.id, + 'global_p': True, + 'perm_read': False, + 'perm_create': False, + 'perm_write': True, + 'perm_delete': False, + 'rules': [('create', [{ + 'domain': json.dumps( + [('relation.field', '!=', 'foo')]), + }])], + }]) + relation, = TestRuleRelation.create([{'field': 'bar'}]) + writable, = TestRule.create([{'relation': relation}]) + + value, = TestRule.read([writable.id], ['_write']) + self.assertEqual(value['_write'], True) + + @with_transaction() + def test_write_field_relation_rule_False(self): + "Test _write field when there's a rule with a relation - False" + pool = Pool() + TestRule = pool.get('test.rule') + TestRuleRelation = pool.get('test.rule.relation') + RuleGroup = pool.get('ir.rule.group') + Model = pool.get('ir.model') + + model, = Model.search([('model', '=', 'test.rule')]) + rule_group, = RuleGroup.create([{ + 'name': "Field different from foo", + 'model': model.id, + 'global_p': True, + 'perm_read': False, + 'perm_create': False, + 'perm_write': True, + 'perm_delete': False, + 'rules': [('create', [{ + 'domain': json.dumps( + [('relation.field', '!=', 'foo')]), + }])], + }]) + relation, = TestRuleRelation.create([{'field': 'foo'}]) + non_writable, = TestRule.create([{'relation': relation}]) + + value, = TestRule.read([non_writable.id], ['_write']) + self.assertEqual(value['_write'], False) + + @with_transaction() + def test_delete_field_no_rule(self): + "Test _delete field when there's no rule" + pool = Pool() + TestRule = pool.get('test.rule') + deletable, = TestRule.create([{'field': 'foo'}]) + + value, = TestRule.read([deletable.id], ['_delete']) + self.assertEqual(value['_delete'], True) + + @with_transaction() + def test_delete_field_rule_True(self): + "Test _delete field when there's a rule - True" + pool = Pool() + TestRule = pool.get('test.rule') + RuleGroup = pool.get('ir.rule.group') + Model = pool.get('ir.model') + + model, = Model.search([('model', '=', 'test.rule')]) + rule_group, = RuleGroup.create([{ + 'name': "Field different from foo", + 'model': model.id, + 'global_p': True, + 'perm_read': False, + 'perm_create': False, + 'perm_write': False, + 'perm_delete': True, + 'rules': [('create', [{ + 'domain': json.dumps( + [('field', '!=', 'foo')]), + }])], + }]) + deletable, = TestRule.create([{'field': 'bar'}]) + + value, = TestRule.read([deletable.id], ['_delete']) + self.assertEqual(value['_delete'], True) + + @with_transaction() + def test_delete_field_rule_False(self): + "Test _delete field when there's a rule - False" + pool = Pool() + TestRule = pool.get('test.rule') + RuleGroup = pool.get('ir.rule.group') + Model = pool.get('ir.model') + + model, = Model.search([('model', '=', 'test.rule')]) + rule_group, = RuleGroup.create([{ + 'name': "Field different from foo", + 'model': model.id, + 'global_p': True, + 'perm_read': False, + 'perm_create': False, + 'perm_write': False, + 'perm_delete': True, + 'rules': [('create', [{ + 'domain': json.dumps( + [('field', '!=', 'foo')]), + }])], + }]) + non_deletable, = TestRule.create([{'field': 'foo'}]) + + value, = TestRule.read([non_deletable.id], ['_delete']) + self.assertEqual(value['_delete'], False) + + @with_transaction() + def test_delete_field_relation_rule_True(self): + "Test _delete field when there's a rule with a relation - True" + pool = Pool() + TestRule = pool.get('test.rule') + TestRuleRelation = pool.get('test.rule.relation') + RuleGroup = pool.get('ir.rule.group') + Model = pool.get('ir.model') + + model, = Model.search([('model', '=', 'test.rule')]) + rule_group, = RuleGroup.create([{ + 'name': "Field different from foo", + 'model': model.id, + 'global_p': True, + 'perm_read': False, + 'perm_create': False, + 'perm_write': False, + 'perm_delete': True, + 'rules': [('create', [{ + 'domain': json.dumps( + [('relation.field', '!=', 'foo')]), + }])], + }]) + relation, = TestRuleRelation.create([{'field': 'bar'}]) + deletable, = TestRule.create([{'relation': relation}]) + + value, = TestRule.read([deletable.id], ['_delete']) + self.assertEqual(value['_delete'], True) + + @with_transaction() + def test_delete_field_relation_rule_False(self): + "Test _delete field when there's a rule with a relation - False" + pool = Pool() + TestRule = pool.get('test.rule') + TestRuleRelation = pool.get('test.rule.relation') + RuleGroup = pool.get('ir.rule.group') + Model = pool.get('ir.model') + + model, = Model.search([('model', '=', 'test.rule')]) + rule_group, = RuleGroup.create([{ + 'name': "Field different from foo", + 'model': model.id, + 'global_p': True, + 'perm_read': False, + 'perm_create': False, + 'perm_write': False, + 'perm_delete': True, + 'rules': [('create', [{ + 'domain': json.dumps( + [('relation.field', '!=', 'foo')]), + }])], + }]) + relation, = TestRuleRelation.create([{'field': 'foo'}]) + non_deletable, = TestRule.create([{'relation': relation}]) + + value, = TestRule.read([non_deletable.id], ['_delete']) + self.assertEqual(value['_delete'], False) + def suite(): suite_ = unittest.TestSuite()