changeset a6df735f91f4 in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset;node=a6df735f91f4
description:
        Store directly sequence type to sequence

        issue10122
        review351381002
diffstat:

 CHANGELOG                               |   2 +
 trytond/ir/message.xml                  |   3 +
 trytond/ir/sequence.py                  |  92 ++++++++++++++++++++------------
 trytond/ir/view/sequence_form.xml       |   4 +-
 trytond/ir/view/sequence_list.xml       |   2 +-
 trytond/ir/view/sequence_type_form.xml  |   2 -
 trytond/ir/view/sequence_type_list.xml  |   1 -
 trytond/res/__init__.py                 |   2 -
 trytond/res/ir.py                       |  38 -------------
 trytond/res/ir.xml                      |   4 +-
 trytond/res/view/sequence_type_form.xml |   4 +-
 trytond/tests/sequence.xml              |   1 -
 trytond/tests/test_ir.py                |  12 +--
 trytond/tests/test_sequence.py          |  49 ++++++++++++-----
 14 files changed, 106 insertions(+), 110 deletions(-)

diffs (506 lines):

diff -r 7007a9104464 -r a6df735f91f4 CHANGELOG
--- a/CHANGELOG Thu Mar 11 19:20:32 2021 +0100
+++ b/CHANGELOG Thu Mar 11 23:00:10 2021 +0100
@@ -1,3 +1,5 @@
+* Use instance method to get next sequence value
+* Store the sequence type directly on sequence
 * Allow sending email with record's attachments
 * Add which records to use for actions
 * Add parent to group to inherit accesses
diff -r 7007a9104464 -r a6df735f91f4 trytond/ir/message.xml
--- a/trytond/ir/message.xml    Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/ir/message.xml    Thu Mar 11 23:00:10 2021 +0100
@@ -264,6 +264,9 @@
         <record model="ir.message" id="msg_sequence_last_timestamp_future">
             <field name="text">The "Last Timestamp" cannot be in the future 
for sequence "%s".</field>
         </record>
+        <record model="ir.message" id="msg_sequence_change_sequence_type">
+            <field name="text">You cannot change the sequence type of a 
sequence instead create a new sequence.</field>
+        </record>
 
         <record model="ir.message" id="msg_language_invalid_grouping">
             <field name="text">Invalid grouping "%(grouping)s" for language 
"%(language)s".</field>
diff -r 7007a9104464 -r a6df735f91f4 trytond/ir/sequence.py
--- a/trytond/ir/sequence.py    Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/ir/sequence.py    Thu Mar 11 23:00:10 2021 +0100
@@ -9,7 +9,7 @@
 from trytond.exceptions import UserError
 from trytond.i18n import gettext
 from trytond.model import ModelView, ModelSQL, DeactivableMixin, fields, Check
-from trytond.model.exceptions import ValidationError
+from trytond.model.exceptions import ValidationError, AccessError
 from trytond.pool import Pool
 from trytond.pyson import Eval, And
 from trytond.transaction import Transaction
@@ -34,7 +34,15 @@
     __name__ = 'ir.sequence.type'
 
     name = fields.Char('Sequence Name', required=True, translate=True)
-    code = fields.Char('Sequence Code', required=True)
+
+    @classmethod
+    def __register__(cls, module):
+        super().__register__(module)
+        table_h = cls.__table_handler__(module)
+
+        # Migration from 5.8: remove code
+        # We keep the column until ir.sequence has been migrated
+        table_h.not_null_action('code', action='remove')
 
 
 class Sequence(DeactivableMixin, ModelSQL, ModelView):
@@ -43,10 +51,13 @@
 
     _strict = False
     name = fields.Char('Sequence Name', required=True, translate=True)
-    code = fields.Selection('code_get', 'Sequence Code', required=True,
+    sequence_type = fields.Many2One(
+        'ir.sequence.type', "Sequence Type",
+        required=True, ondelete='RESTRICT',
         states={
-            'readonly': Eval('context', {}).contains('code'),
-            })
+            'readonly': Eval('id', -1) >= 0,
+            },
+        depends=['id'])
     prefix = fields.Char('Prefix')
     suffix = fields.Char('Suffix')
     type = fields.Selection([
@@ -100,6 +111,29 @@
                 'Timestamp rounding should be greater than 0'),
             ]
 
+    @classmethod
+    def __register__(cls, module):
+        pool = Pool()
+        SequenceType = pool.get('ir.sequence.type')
+        cursor = Transaction().connection.cursor()
+        table = cls.__table__()
+        sequence_type = SequenceType.__table__()
+
+        super().__register__(module)
+
+        table_h = cls.__table_handler__(module)
+
+        # Migration from 5.8: replace code by sequence_type
+        if table_h.column_exist('code'):
+            cursor.execute(*table.update(
+                    [table.sequence_type],
+                    sequence_type.select(
+                        sequence_type.id,
+                        where=sequence_type.code == table.code)))
+            table_h.drop_column('code')
+            sequence_type_h = SequenceType.__table_handler__(module)
+            sequence_type_h.drop_column('code')
+
     @staticmethod
     def default_type():
         return 'incremental'
@@ -128,10 +162,6 @@
     def default_last_timestamp():
         return 0
 
-    @staticmethod
-    def default_code():
-        return Transaction().context.get('code')
-
     def get_number_next(self, name):
         if self.type != 'incremental':
             return
@@ -171,10 +201,17 @@
         return sequences
 
     @classmethod
-    def write(cls, sequences, values, *args):
-        super(Sequence, cls).write(sequences, values, *args)
+    def write(cls, *args):
+        transaction = Transaction()
+        if (transaction.user != 0
+                and transaction.context.get('_check_access')):
+            for values in args[1::2]:
+                if 'sequence_type' in values:
+                    raise AccessError(gettext(
+                            'ir.msg_sequence_change_sequence_type'))
+        super().write(*args)
         if sql_sequence and not cls._strict:
-            actions = iter((sequences, values) + args)
+            actions = iter(args)
             for sequences, values in zip(actions, actions):
                 for sequence in sequences:
                     sequence.update_sql_sequence(values.get('number_next'))
@@ -187,13 +224,6 @@
         return super(Sequence, cls).delete(sequences)
 
     @classmethod
-    def code_get(cls):
-        pool = Pool()
-        SequenceType = pool.get('ir.sequence.type')
-        sequence_types = SequenceType.search([])
-        return [(x.code, x.name) for x in sequence_types]
-
-    @classmethod
     def validate(cls, sequences):
         super(Sequence, cls).validate(sequences)
         cls.check_affixes(sequences)
@@ -323,21 +353,16 @@
                 return hex(timestamp)[2:].upper()
         return ''
 
-    @classmethod
-    def get_id(cls, domain, _lock=False):
-        '''
-        Return sequence value for the domain
+    def get(self, _lock=False):
         '''
-        if isinstance(domain, cls):
-            domain = domain.id
-        if isinstance(domain, int):
-            domain = [('id', '=', domain)]
-
+        Return the next sequence value
+        '''
+        cls = self.__class__
         # bypass rules on sequences
         with Transaction().set_context(user=False, _check_access=False):
             with Transaction().set_user(0):
                 try:
-                    sequence, = cls.search(domain, limit=1)
+                    sequence = cls(self.id)
                 except TypeError:
                     raise MissingError(gettext('ir.msg_sequence_missing'))
                 if _lock:
@@ -360,10 +385,6 @@
                     cls._process(sequence.suffix, date=date),
                     )
 
-    @classmethod
-    def get(cls, code):
-        return cls.get_id([('code', '=', code)])
-
 
 class SequenceStrict(Sequence):
     "Sequence Strict"
@@ -371,6 +392,5 @@
     _table = None  # Needed to reset Sequence._table
     _strict = True
 
-    @classmethod
-    def get_id(cls, clause):
-        return super(SequenceStrict, cls).get_id(clause, _lock=True)
+    def get(self, _lock=True):
+        return super().get(_lock=True)
diff -r 7007a9104464 -r a6df735f91f4 trytond/ir/view/sequence_form.xml
--- a/trytond/ir/view/sequence_form.xml Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/ir/view/sequence_form.xml Thu Mar 11 23:00:10 2021 +0100
@@ -4,8 +4,8 @@
 <form>
     <label name="name"/>
     <field name="name" colspan="3"/>
-    <label name="code"/>
-    <field name="code"/>
+    <label name="sequence_type"/>
+    <field name="sequence_type" widget="selection"/>
     <label name="active"/>
     <field name="active"/>
     <label name="prefix"/>
diff -r 7007a9104464 -r a6df735f91f4 trytond/ir/view/sequence_list.xml
--- a/trytond/ir/view/sequence_list.xml Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/ir/view/sequence_list.xml Thu Mar 11 23:00:10 2021 +0100
@@ -3,6 +3,6 @@
 this repository contains the full copyright notices and license terms. -->
 <tree>
     <field name="name" expand="2"/>
-    <field name="code" expand="1"/>
+    <field name="sequence_type" expand="1"/>
     <field name="type"/>
 </tree>
diff -r 7007a9104464 -r a6df735f91f4 trytond/ir/view/sequence_type_form.xml
--- a/trytond/ir/view/sequence_type_form.xml    Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/ir/view/sequence_type_form.xml    Thu Mar 11 23:00:10 2021 +0100
@@ -4,6 +4,4 @@
 <form>
     <label name="name"/>
     <field name="name"/>
-    <label name="code"/>
-    <field name="code" readonly="1"/>
 </form>
diff -r 7007a9104464 -r a6df735f91f4 trytond/ir/view/sequence_type_list.xml
--- a/trytond/ir/view/sequence_type_list.xml    Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/ir/view/sequence_type_list.xml    Thu Mar 11 23:00:10 2021 +0100
@@ -3,5 +3,4 @@
 this repository contains the full copyright notices and license terms. -->
 <tree>
     <field name="name" expand="2"/>
-    <field name="code" expand="1"/>
 </tree>
diff -r 7007a9104464 -r a6df735f91f4 trytond/res/__init__.py
--- a/trytond/res/__init__.py   Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/res/__init__.py   Thu Mar 11 23:00:10 2021 +0100
@@ -36,8 +36,6 @@
         ir.Lang,
         ir.SequenceType,
         ir.SequenceTypeGroup,
-        ir.Sequence,
-        ir.SequenceStrict,
         ir.ModuleConfigWizardItem,
         ir.Export,
         ir.Export_Group,
diff -r 7007a9104464 -r a6df735f91f4 trytond/res/ir.py
--- a/trytond/res/ir.py Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/res/ir.py Thu Mar 11 23:00:10 2021 +0100
@@ -224,44 +224,6 @@
         Rule._domain_get_cache.clear()
 
 
-class Sequence(metaclass=PoolMeta):
-    __name__ = 'ir.sequence'
-    groups = fields.Function(fields.Many2Many('res.group', None, None,
-        'User Groups'), 'get_groups', searcher='search_groups')
-
-    @classmethod
-    def get_groups(cls, sequences, name):
-        SequenceType = Pool().get('ir.sequence.type')
-        code2seq = {}
-        for sequence in sequences:
-            code2seq.setdefault(sequence.code, []).append(sequence.id)
-
-        sequence_types = SequenceType.search([
-                ('code', 'in', list(code2seq.keys())),
-                ])
-
-        groups = {}
-        for sequence_type in sequence_types:
-            seq_ids = code2seq[sequence_type.code]
-            for seq_id in seq_ids:
-                groups.setdefault(seq_id, []).append(sequence_type.id)
-
-        return groups
-
-    @staticmethod
-    def search_groups(name, clause):
-        SequenceType = Pool().get('ir.sequence.type')
-        seq_types = SequenceType.search([clause], order=[])
-        codes = set(st.code for st in seq_types)
-        return [('code', 'in', list(codes))]
-
-
-class SequenceStrict(Sequence):
-    # This empty class declaration is needed to inherit the groups
-    # field
-    __name__ = 'ir.sequence.strict'
-
-
 class ModuleConfigWizardItem(metaclass=PoolMeta):
     __name__ = 'ir.module.config_wizard.item'
 
diff -r 7007a9104464 -r a6df735f91f4 trytond/res/ir.xml
--- a/trytond/res/ir.xml        Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/res/ir.xml        Thu Mar 11 23:00:10 2021 +0100
@@ -778,7 +778,7 @@
         </record>
         <record model="ir.rule" id="rule_sequence">
             <field name="domain"
-                eval="[('groups', 'in', Eval('groups', []))]"
+                eval="[('sequence_type.groups', 'in', Eval('groups', []))]"
                 pyson="1"/>
             <field name="rule_group" ref="rule_group_sequence"/>
         </record>
@@ -791,7 +791,7 @@
         </record>
         <record model="ir.rule" id="rule_sequence_strict">
             <field name="domain"
-                eval="[('groups', 'in', Eval('groups', []))]"
+                eval="[('sequence_type.groups', 'in', Eval('groups', []))]"
                 pyson="1"/>
             <field name="rule_group" ref="rule_group_sequence_strict"/>
         </record>
diff -r 7007a9104464 -r a6df735f91f4 trytond/res/view/sequence_type_form.xml
--- a/trytond/res/view/sequence_type_form.xml   Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/res/view/sequence_type_form.xml   Thu Mar 11 23:00:10 2021 +0100
@@ -2,9 +2,7 @@
 <!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
 this repository contains the full copyright notices and license terms. -->
 <data>
-    <xpath
-        expr="/form/field[@name='code']"
-        position="after">
+    <xpath expr="/form" position="inside">
       <field name="groups" colspan="4"/>
     </xpath>
 </data>
diff -r 7007a9104464 -r a6df735f91f4 trytond/tests/sequence.xml
--- a/trytond/tests/sequence.xml        Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/tests/sequence.xml        Thu Mar 11 23:00:10 2021 +0100
@@ -6,7 +6,6 @@
 
         <record model="ir.sequence.type" id="sequence_type_test">
             <field name="name">Test</field>
-            <field name="code">test</field>
         </record>
         <record model="ir.sequence.type-res.group"
             id="sequence_type_test_group_admin">
diff -r 7007a9104464 -r a6df735f91f4 trytond/tests/test_ir.py
--- a/trytond/tests/test_ir.py  Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/tests/test_ir.py  Thu Mar 11 23:00:10 2021 +0100
@@ -31,20 +31,18 @@
         except KeyError:
             groups = []
 
-        sequence_type = SequenceType(name='Test', code='test', groups=groups)
+        sequence_type = SequenceType(name='Test', groups=groups)
         sequence_type.save()
-        sequence = Sequence(name='Test Sequence', code='test')
+        sequence = Sequence(name='Test Sequence', sequence_type=sequence_type)
         sequence.save()
-        self.assertEqual(Sequence.get_id(sequence.id), '1')
+        self.assertEqual(sequence.get(), '1')
         today = Date.today()
         sequence.prefix = '${year}'
         sequence.save()
-        self.assertEqual(Sequence.get_id(sequence.id),
-            '%s2' % str(today.year))
+        self.assertEqual(sequence.get(), '%s2' % str(today.year))
         next_year = today + relativedelta(years=1)
         with Transaction().set_context(date=next_year):
-            self.assertEqual(Sequence.get_id(sequence.id),
-                '%s3' % str(next_year.year))
+            self.assertEqual(sequence.get(), '%s3' % str(next_year.year))
 
     @with_transaction()
     def test_global_search(self):
diff -r 7007a9104464 -r a6df735f91f4 trytond/tests/test_sequence.py
--- a/trytond/tests/test_sequence.py    Thu Mar 11 19:20:32 2021 +0100
+++ b/trytond/tests/test_sequence.py    Thu Mar 11 23:00:10 2021 +0100
@@ -24,49 +24,59 @@
     @with_transaction()
     def test_incremental(self):
         'Test incremental'
+        pool = Pool()
         Sequence = self.get_model()
+        SequenceType = pool.get('ir.sequence.type')
 
+        sequence_type, = SequenceType.search([
+                ('name', '=', "Test"),
+                ], limit=1)
         sequence, = Sequence.create([{
                     'name': 'Test incremental',
-                    'code': 'test',
+                    'sequence_type': sequence_type.id,
                     'prefix': '',
                     'suffix': '',
                     'type': 'incremental',
                     }])
         self.assertEqual(sequence.number_next, 1)
-        self.assertEqual(Sequence.get_id(sequence), '1')
+        self.assertEqual(sequence.get(), '1')
 
         Sequence.write([sequence], {
                 'number_increment': 10,
                 })
         self.assertEqual(sequence.number_next, 2)
-        self.assertEqual(Sequence.get_id(sequence), '2')
-        self.assertEqual(Sequence.get_id(sequence), '12')
+        self.assertEqual(sequence.get(), '2')
+        self.assertEqual(sequence.get(), '12')
 
         Sequence.write([sequence], {
                 'padding': 3,
                 })
         self.assertEqual(sequence.number_next, 22)
-        self.assertEqual(Sequence.get_id(sequence), '022')
+        self.assertEqual(sequence.get(), '022')
 
     @with_transaction()
     def test_decimal_timestamp(self):
         'Test Decimal Timestamp'
+        pool = Pool()
         Sequence = self.get_model()
+        SequenceType = pool.get('ir.sequence.type')
 
+        sequence_type, = SequenceType.search([
+                ('name', '=', "Test"),
+                ], limit=1)
         sequence, = Sequence.create([{
                     'name': 'Test decimal timestamp',
-                    'code': 'test',
+                    'sequence_type': sequence_type.id,
                     'prefix': '',
                     'suffix': '',
                     'type': 'decimal timestamp',
                     }])
-        timestamp = Sequence.get_id(sequence)
+        timestamp = sequence.get()
         self.assertEqual(timestamp, str(sequence.last_timestamp))
 
         self.assertEqual(sequence.number_next, None)
 
-        self.assertNotEqual(Sequence.get_id(sequence), timestamp)
+        self.assertNotEqual(sequence.get(), timestamp)
 
         next_timestamp = Sequence._timestamp(sequence)
         self.assertRaises(LastTimestampError, Sequence.write, [sequence], {
@@ -76,22 +86,27 @@
     @with_transaction()
     def test_hexadecimal_timestamp(self):
         'Test Hexadecimal Timestamp'
+        pool = Pool()
         Sequence = self.get_model()
+        SequenceType = pool.get('ir.sequence.type')
 
+        sequence_type, = SequenceType.search([
+                ('name', '=', "Test"),
+                ], limit=1)
         sequence, = Sequence.create([{
                     'name': 'Test hexadecimal timestamp',
-                    'code': 'test',
+                    'sequence_type': sequence_type.id,
                     'prefix': '',
                     'suffix': '',
                     'type': 'hexadecimal timestamp',
                     }])
-        timestamp = Sequence.get_id(sequence)
+        timestamp = sequence.get()
         self.assertEqual(timestamp,
             hex(int(sequence.last_timestamp))[2:].upper())
 
         self.assertEqual(sequence.number_next, None)
 
-        self.assertNotEqual(Sequence.get_id(sequence), timestamp)
+        self.assertNotEqual(sequence.get(), timestamp)
 
         next_timestamp = Sequence._timestamp(sequence)
         self.assertRaises(LastTimestampError, Sequence.write, [sequence], {
@@ -101,16 +116,21 @@
     @with_transaction()
     def test_prefix_suffix(self):
         'Test prefix/suffix'
+        pool = Pool()
         Sequence = self.get_model()
+        SequenceType = pool.get('ir.sequence.type')
 
+        sequence_type, = SequenceType.search([
+                ('name', '=', "Test"),
+                ], limit=1)
         sequence, = Sequence.create([{
                     'name': 'Test incremental',
-                    'code': 'test',
+                    'sequence_type': sequence_type.id,
                     'prefix': 'prefix/',
                     'suffix': '/suffix',
                     'type': 'incremental',
                     }])
-        self.assertEqual(Sequence.get_id(sequence),
+        self.assertEqual(sequence.get(),
             'prefix/1/suffix')
 
         Sequence.write([sequence], {
@@ -118,8 +138,7 @@
                 'suffix': '/${day}.${month}.${year}',
                 })
         with Transaction().set_context(date=datetime.date(2010, 8, 15)):
-            self.assertEqual(Sequence.get_id(sequence),
-                '2010-08-15/2/15.08.2010')
+            self.assertEqual(sequence.get(), '2010-08-15/2/15.08.2010')
 
 
 class SequenceStrictTestCase(SequenceTestCase):

Reply via email to