From 1f88e3a61efef3b42465bf2e084f6fb50d338a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 11 Oct 2022 00:44:50 +0200 Subject: [PATCH] Use declarative index definition for ModelSQL issue5757 review361251002 --- inventory.py | 9 ++- location.py | 27 +++++---- move.py | 155 +++++++++++++++++++++++++-------------------------- party.py | 3 +- period.py | 41 +++++++++++--- product.py | 13 ++++- shipment.py | 92 ++++++++++++++++++++++++------ 7 files changed, 216 insertions(+), 124 deletions(-) diff --git a/inventory.py b/inventory.py index c60def0525..798753b0d0 100644 --- a/inventory.py +++ b/inventory.py @@ -5,7 +5,8 @@ from collections import defaultdict from sql import Null from trytond.i18n import gettext -from trytond.model import Check, Model, ModelSQL, ModelView, Workflow, fields +from trytond.model import ( + Check, Index, Model, ModelSQL, ModelView, Workflow, fields) from trytond.model.exceptions import AccessError from trytond.pool import Pool from trytond.pyson import Bool, Eval, If @@ -59,7 +60,7 @@ class Inventory(Workflow, ModelSQL, ModelView): ('draft', "Draft"), ('done', "Done"), ('cancelled', "Cancelled"), - ], "State", readonly=True, select=True, sort=False, + ], "State", readonly=True, sort=False, help="The current state of the inventory.") del _states @@ -67,7 +68,9 @@ class Inventory(Workflow, ModelSQL, ModelView): @classmethod def __setup__(cls): super(Inventory, cls).__setup__() - cls.create_date.select = True + t = cls.__table__() + cls._sql_indexes.add( + Index(t, (t.state, Index.Equality()), where=t.state == 'draft')) cls._order.insert(0, ('date', 'DESC')) cls._transitions |= set(( ('draft', 'done'), diff --git a/location.py b/location.py index daa38d31bc..2afdb72505 100644 --- a/location.py +++ b/location.py @@ -9,7 +9,7 @@ from sql import Column from trytond.cache import Cache from trytond.i18n import gettext from trytond.model import ( - DeactivableMixin, MatchMixin, Model, ModelSQL, ModelView, fields, + DeactivableMixin, Index, MatchMixin, Model, ModelSQL, ModelView, fields, sequence_ordered, tree) from trytond.modules.product import price_digits, round_price from trytond.pool import Pool @@ -40,7 +40,7 @@ class Location(DeactivableMixin, tree(), ModelSQL, ModelView): name = fields.Char("Name", size=None, required=True, translate=True) code = fields.Char( - "Code", size=None, select=True, + "Code", help="The internal identifier used for the location.") address = fields.Many2One( 'party.address', "Address", @@ -58,11 +58,12 @@ class Location(DeactivableMixin, tree(), ModelSQL, ModelView): ('view', 'View'), ], "Location type") type_string = type.translated('type') - parent = fields.Many2One("stock.location", "Parent", select=True, + parent = fields.Many2One( + "stock.location", "Parent", left="left", right="right", help="Used to add structure above the location.") - left = fields.Integer('Left', required=True, select=True) - right = fields.Integer('Right', required=True, select=True) + left = fields.Integer('Left', required=True) + right = fields.Integer('Right', required=True) childs = fields.One2Many("stock.location", "parent", "Children", help="Used to add structure below the location.") flat_childs = fields.Boolean( @@ -177,7 +178,16 @@ class Location(DeactivableMixin, tree(), ModelSQL, ModelView): @classmethod def __setup__(cls): + cls.code.search_unaccented = False super(Location, cls).__setup__() + t = cls.__table__() + cls._sql_indexes.update({ + Index(t, (t.code, Index.Similarity())), + Index( + t, + (t.left, Index.Range()), + (t.right, Index.Range())), + }) cls._order.insert(0, ('name', 'ASC')) parent_domain = [ @@ -223,13 +233,6 @@ class Location(DeactivableMixin, tree(), ModelSQL, ModelView): childs_domain[parent].append(type_) return childs_domain - @classmethod - def __register__(cls, module_name): - super(Location, cls).__register__(module_name) - - table = cls.__table_handler__(module_name) - table.index_action(['left', 'right'], 'add') - @classmethod def validate_fields(cls, locations, field_names): super().validate_fields(locations, field_names) diff --git a/move.py b/move.py index 4ec4a5241a..9e439bfe95 100644 --- a/move.py +++ b/move.py @@ -13,7 +13,8 @@ from sql.conditionals import Case, Coalesce from sql.functions import Round from trytond.i18n import gettext -from trytond.model import Check, Model, ModelSQL, ModelView, Workflow, fields +from trytond.model import ( + Check, Index, Model, ModelSQL, ModelView, Workflow, fields) from trytond.model.exceptions import AccessError from trytond.modules.product import price_digits, round_price from trytond.pool import Pool @@ -176,8 +177,8 @@ class Move(Workflow, ModelSQL, ModelView): "Stock Move" __name__ = 'stock.move' _order_name = 'product' - product = fields.Many2One("product.product", "Product", required=True, - select=True, states=STATES, + product = fields.Many2One( + 'product.product', "Product", required=True, states=STATES, context={ 'company': Eval('company', -1), }, @@ -203,32 +204,37 @@ class Move(Workflow, ModelSQL, ModelView): help="The amount of stock moved.") internal_quantity = fields.Float('Internal Quantity', readonly=True, required=True) - from_location = fields.Many2One("stock.location", "From Location", - select=True, required=True, states=STATES, + from_location = fields.Many2One( + 'stock.location', "From Location", + required=True, states=STATES, domain=LOCATION_DOMAIN, help="Where the stock is moved from.") - to_location = fields.Many2One("stock.location", "To Location", select=True, + to_location = fields.Many2One( + 'stock.location', "To Location", required=True, states=STATES, domain=LOCATION_DOMAIN, help="Where the stock is moved to.") - shipment = fields.Reference('Shipment', selection='get_shipment', - readonly=True, select=True, + shipment = fields.Reference( + "Shipment", selection='get_shipment', readonly=True, states={ 'invisible': ~Eval('shipment'), }, help="Used to group several stock moves together.") - origin = fields.Reference('Origin', selection='get_origin', select=True, + origin = fields.Reference( + "Origin", selection='get_origin', states={ 'readonly': Eval('state') != 'draft', }, help="The source of the stock move.") - planned_date = fields.Date("Planned Date", states={ + planned_date = fields.Date( + "Planned Date", + states={ 'readonly': (Eval('state').in_(['cancelled', 'assigned', 'done']) | Eval('shipment')) }, - select=True, help="When the stock is expected to be moved.") - effective_date = fields.Date("Effective Date", select=True, + effective_date = fields.Date( + "Effective Date", states={ 'required': Eval('state') == 'done', 'readonly': (Eval('state').in_(['cancelled', 'done']) @@ -241,7 +247,7 @@ class Move(Workflow, ModelSQL, ModelView): ('assigned', 'Assigned'), ('done', 'Done'), ('cancelled', 'Cancelled'), - ], "State", select=True, readonly=True, sort=False, + ], "State", readonly=True, sort=False, help="The current state of the stock move.") company = fields.Many2One( 'company.company', "Company", required=True, @@ -296,7 +302,6 @@ class Move(Workflow, ModelSQL, ModelView): @classmethod def __setup__(cls): super(Move, cls).__setup__() - cls.create_date.select = True cls.product.domain = [ If(Bool(Eval('product_uom_category')) & ~Eval('state').in_(['done', 'cancelled']), @@ -322,6 +327,30 @@ class Move(Workflow, ModelSQL, ModelView): Check(t, t.from_location != t.to_location), 'stock.msg_move_from_to_location'), ] + cls._sql_indexes.update({ + Index( + t, + (t.from_location, Index.Range()), + (t.product, Index.Range()), + (Coalesce( + t.effective_date, + t.planned_date, + datetime.date.max), + Index.Range())), + Index( + t, + (t.to_location, Index.Range()), + (t.product, Index.Range()), + (Coalesce( + t.effective_date, + t.planned_date, + datetime.date.max), + Index.Range())), + Index( + t, + (t.state, Index.Equality()), + where=t.state.in_(['staging', 'draft', 'assigned'])), + }) cls._order[0] = ('id', 'DESC') cls._transitions |= set(( ('staging', 'draft'), @@ -360,13 +389,6 @@ class Move(Workflow, ModelSQL, ModelView): sql_table = cls.__table__() super(Move, cls).__register__(module_name) - table = cls.__table_handler__(module_name) - - # Index for period join in compute_quantities_query - table.index_action([ - Coalesce(sql_table.effective_date, - sql_table.planned_date, - datetime.date.max)], action='add') # Migration from 5.6: rename state cancel to cancelled cursor.execute(*sql_table.update( @@ -1312,11 +1334,8 @@ class Move(Workflow, ModelSQL, ModelView): return (move.state.in_(['done', 'assigned' if stock_assign else 'done']) & ( - ( - (move.effective_date == Null) - & (move.planned_date <= context['stock_date_end']) - ) - | (move.effective_date <= context['stock_date_end']) + (Coalesce(move.effective_date, move.planned_date) + <= context['stock_date_end']) | (move.state == ( 'assigned' if not context.get('stock_date_start') @@ -1333,11 +1352,11 @@ class Move(Workflow, ModelSQL, ModelView): return ((move.state.in_(['done', 'assigned' if stock_assign else 'done']) & ( - ( - (move.effective_date == Null) - & (move.planned_date <= today) - ) - | (move.effective_date <= today) + (Coalesce( + move.effective_date, + move.planned_date, + datetime.date.max) + <= today) | (move.state == ( 'assigned' if not context.get('stock_date_start') @@ -1347,19 +1366,17 @@ class Move(Workflow, ModelSQL, ModelView): | (move.state.in_(['done', 'assigned', 'draft']) & ( ( - (move.effective_date == Null) - & (Coalesce( - move.planned_date, datetime.date.max) + (Coalesce( + move.effective_date, + move.planned_date, + datetime.date.max) <= context['stock_date_end']) & (Coalesce( - move.planned_date, datetime.date.max) + move.effective_date, + move.planned_date, + datetime.date.max) >= today) ) - | ( - (move.effective_date - <= context['stock_date_end']) - & (move.effective_date >= today) - ) | (move.state == ( 'assigned' if not context.get('stock_date_start') @@ -1375,18 +1392,11 @@ class Move(Workflow, ModelSQL, ModelView): if context['stock_date_start'] > today: def state_date_clause(): return (move.state.in_(['done', 'assigned', 'draft']) - & ( - ( - (move.effective_date == Null) - & ( - (move.planned_date - >= context['stock_date_start']) - | (move.planned_date == Null) - ) - ) - | (move.effective_date - >= context['stock_date_start']) - ) + & (Coalesce( + move.effective_date, + move.planned_date, + datetime.date.max) + >= context['stock_date_start']) ) state_date_clause_in &= state_date_clause() state_date_clause_out &= state_date_clause() @@ -1394,38 +1404,23 @@ class Move(Workflow, ModelSQL, ModelView): def state_date_clause(stock_assign): return (( move.state.in_(['done', 'assigned', 'draft']) - & ( - ( - (move.effective_date == Null) - & ( - (move.planned_date >= today) - | (move.planned_date == Null) - ) - ) - | (move.effective_date >= today) - ) + & (Coalesce( + move.effective_date, + move.planned_date, + datetime.date.max) >= today) ) | ( move.state.in_(['done', 'assigned' if stock_assign else 'done']) - & ( - ( - (move.effective_date == Null) - & ( - ( - (move.planned_date - >= context['stock_date_start']) - & (move.planned_date < today) - ) - | (move.planned_date == Null) - ) - ) - | ( - (move.effective_date - >= context['stock_date_start']) - & (move.effective_date < today) - ) - ) + & (Coalesce( + move.effective_date, + move.planned_date, + datetime.date.max) + >= context['stock_date_start']) + & (Coalesce( + move.effective_date, + move.planned_date, + datetime.date.min) < today) ) ) state_date_clause_in &= state_date_clause(False) diff --git a/party.py b/party.py index 74c1164aef..d0bbc151dd 100644 --- a/party.py +++ b/party.py @@ -66,8 +66,7 @@ class Party(metaclass=PoolMeta): class PartyLocation(ModelSQL, ValueMixin): "Party Location" __name__ = 'party.party.location' - party = fields.Many2One( - 'party.party', "Party", ondelete='CASCADE', select=True) + party = fields.Many2One('party.party', "Party", ondelete='CASCADE') supplier_location = supplier_location customer_location = customer_location diff --git a/period.py b/period.py index c02f306c04..64d8603a72 100644 --- a/period.py +++ b/period.py @@ -5,7 +5,7 @@ from itertools import chain, groupby from sql import For, Literal from trytond.i18n import gettext -from trytond.model import ModelSQL, ModelView, Workflow, fields +from trytond.model import Index, ModelSQL, ModelView, Workflow, fields from trytond.pool import Pool from trytond.pyson import Eval from trytond.tools import grouped_slice @@ -29,12 +29,19 @@ class Period(Workflow, ModelSQL, ModelView): state = fields.Selection([ ('draft', 'Draft'), ('closed', 'Closed'), - ], "State", select=True, readonly=True, sort=False, + ], "State", readonly=True, sort=False, help="The current state of the stock period.") @classmethod def __setup__(cls): super(Period, cls).__setup__() + t = cls.__table__() + cls._sql_indexes.add( + Index( + t, + (t.company, Index.Equality()), + (t.date, Index.Range(order='DESC')), + where=t.state == 'closed')) cls._transitions |= set(( ('draft', 'closed'), ('closed', 'draft'), @@ -164,10 +171,28 @@ class Cache(ModelSQL, ModelView): It is used to store cached computation of stock quantities. ''' __name__ = 'stock.period.cache' - period = fields.Many2One('stock.period', 'Period', required=True, - readonly=True, select=True, ondelete='CASCADE') - location = fields.Many2One('stock.location', 'Location', required=True, - readonly=True, select=True, ondelete='CASCADE') - product = fields.Many2One('product.product', 'Product', required=True, - readonly=True, select=True, ondelete='CASCADE') + period = fields.Many2One( + 'stock.period', "Period", + required=True, readonly=True, ondelete='CASCADE') + location = fields.Many2One( + 'stock.location', "Location", + required=True, readonly=True, ondelete='CASCADE') + product = fields.Many2One( + 'product.product', "Product", + required=True, readonly=True, ondelete='CASCADE') internal_quantity = fields.Float('Internal Quantity', readonly=True) + + @classmethod + def __setup__(cls): + super().__setup__() + t = cls.__table__() + cls._sql_indexes.update({ + Index( + t, + (t.period, Index.Equality()), + (t.product, Index.Equality()), + include=[t.internal_quantity]), + Index( + t, + (t.location, Index.Equality())), + }) diff --git a/product.py b/product.py index 6a45f6191f..90ae57b3ea 100644 --- a/product.py +++ b/product.py @@ -14,7 +14,7 @@ from sql.functions import CurrentTimestamp from sql.operators import Concat from trytond.i18n import gettext -from trytond.model import ModelSQL, ModelView, fields +from trytond.model import Index, ModelSQL, ModelView, fields from trytond.model.exceptions import AccessError from trytond.modules.product import price_digits, round_price from trytond.pool import Pool, PoolMeta @@ -1184,7 +1184,7 @@ class CostPriceRevision(ModelSQL, ModifyCostPriceStart): __name__ = 'product.cost_price.revision' template = fields.Many2One( 'product.template', "Product", - ondelete='CASCADE', select=True, required=True, + ondelete='CASCADE', required=True, domain=[ If(Bool(Eval('product')), ('products', '=', Eval('product')), @@ -1196,7 +1196,7 @@ class CostPriceRevision(ModelSQL, ModifyCostPriceStart): depends={'company'}) product = fields.Many2One( 'product.product', "Variant", - ondelete='CASCADE', select=True, + ondelete='CASCADE', domain=[ If(Bool(Eval('template')), ('template', '=', Eval('template')), @@ -1212,6 +1212,13 @@ class CostPriceRevision(ModelSQL, ModifyCostPriceStart): @classmethod def __setup__(cls): super().__setup__() + t = cls.__table__() + cls._sql_indexes.add( + Index( + t, + (t.product, Index.Equality()), + (t.template, Index.Equality()), + (t.company, Index.Equality()))) cls._order.insert(0, ('date', 'DESC')) @classmethod diff --git a/shipment.py b/shipment.py index 13a9d462f1..051dc4c995 100644 --- a/shipment.py +++ b/shipment.py @@ -11,7 +11,8 @@ from sql.conditionals import Coalesce from sql.functions import CharLength from trytond.i18n import gettext -from trytond.model import ModelSQL, ModelView, Workflow, dualmethod, fields +from trytond.model import ( + Index, ModelSQL, ModelView, Workflow, dualmethod, fields) from trytond.model.exceptions import AccessError from trytond.modules.company import CompanyReport from trytond.modules.company.model import employee_field, set_employee @@ -140,7 +141,8 @@ class ShipmentIn(ShipmentMixin, Workflow, ModelSQL, ModelView): 'readonly': Eval('state') != 'draft', }, help="The company the shipment is associated with.") - reference = fields.Char("Reference", size=None, select=True, + reference = fields.Char( + "Reference", states={ 'readonly': Eval('state') != 'draft', }, @@ -227,7 +229,8 @@ class ShipmentIn(ShipmentMixin, Workflow, ModelSQL, ModelView): moves = fields.One2Many('stock.move', 'shipment', 'Moves', domain=[('company', '=', Eval('company'))], readonly=True) origins = fields.Function(fields.Char('Origins'), 'get_origins') - number = fields.Char('Number', size=None, select=True, readonly=True, + number = fields.Char( + "Number", readonly=True, help="The main identifier for the shipment.") received_by = employee_field("Received By") done_by = employee_field("Done By") @@ -241,8 +244,17 @@ class ShipmentIn(ShipmentMixin, Workflow, ModelSQL, ModelView): @classmethod def __setup__(cls): + cls.number.search_unaccented = False + cls.reference.search_unaccented = False super(ShipmentIn, cls).__setup__() - cls.create_date.select = True + t = cls.__table__() + cls._sql_indexes.update({ + Index(t, (t.reference, Index.Similarity())), + Index( + t, + (t.state, Index.Equality()), + where=t.state.in_(['draft', 'received'])), + }) cls._order = [ ('id', 'DESC'), ] @@ -585,9 +597,11 @@ class ShipmentInReturn(ShipmentAssignMixin, Workflow, ModelSQL, ModelView): 'readonly': Eval('state') != 'draft', }, help="The company the shipment is associated with.") - number = fields.Char('Number', size=None, select=True, readonly=True, + number = fields.Char( + "Number", readonly=True, help="The main identifier for the shipment.") - reference = fields.Char("Reference", size=None, select=True, + reference = fields.Char( + "Reference", states={ 'readonly': Eval('state') != 'draft', }, @@ -664,8 +678,17 @@ class ShipmentInReturn(ShipmentAssignMixin, Workflow, ModelSQL, ModelView): @classmethod def __setup__(cls): + cls.number.search_unaccented = False + cls.reference.search_unaccented = False super(ShipmentInReturn, cls).__setup__() - cls.create_date.select = True + t = cls.__table__() + cls._sql_indexes.update({ + Index(t, (t.reference, Index.Similarity())), + Index( + t, + (t.state, Index.Equality()), + where=t.state.in_(['draft', 'waiting', 'assigned'])), + }) cls._order = [ ('effective_date', 'ASC NULLS LAST'), ('id', 'ASC'), @@ -991,7 +1014,8 @@ class ShipmentOut(ShipmentAssignMixin, Workflow, ModelSQL, ModelView): ]), ], help="Where the stock is sent to.") - reference = fields.Char("Reference", size=None, select=True, + reference = fields.Char( + "Reference", states={ 'readonly': Eval('state') != 'draft', }, @@ -1045,7 +1069,8 @@ class ShipmentOut(ShipmentAssignMixin, Workflow, ModelSQL, ModelView): moves = fields.One2Many('stock.move', 'shipment', 'Moves', domain=[('company', '=', Eval('company'))], readonly=True) origins = fields.Function(fields.Char('Origins'), 'get_origins') - number = fields.Char('Number', size=None, select=True, readonly=True, + number = fields.Char( + "Number", readonly=True, help="The main identifier for the shipment.") picked_by = employee_field("Picked By") packed_by = employee_field("Packed By") @@ -1063,8 +1088,19 @@ class ShipmentOut(ShipmentAssignMixin, Workflow, ModelSQL, ModelView): @classmethod def __setup__(cls): + cls.number.search_unaccented = False + cls.reference.search_unaccented = False super(ShipmentOut, cls).__setup__() - cls.create_date.select = True + t = cls.__table__() + cls._sql_indexes.update({ + Index(t, (t.reference, Index.Similarity())), + Index( + t, + (t.state, Index.Equality()), + where=t.state.in_([ + 'draft', 'waiting', 'assigned', + 'picked', 'packed'])), + }) cls._order = [ ('effective_date', 'ASC NULLS LAST'), ('id', 'ASC'), @@ -1661,7 +1697,8 @@ class ShipmentOutReturn(ShipmentMixin, Workflow, ModelSQL, ModelView): 'readonly': Eval('state') != 'draft', }, domain=[('party', '=', Eval('customer'))], help="The address the customer can be contacted at.") - reference = fields.Char("Reference", size=None, select=True, + reference = fields.Char( + "Reference", states={ 'readonly': Eval('state') != 'draft', }, @@ -1716,7 +1753,8 @@ class ShipmentOutReturn(ShipmentMixin, Workflow, ModelSQL, ModelView): moves = fields.One2Many('stock.move', 'shipment', 'Moves', domain=[('company', '=', Eval('company'))], readonly=True) origins = fields.Function(fields.Char('Origins'), 'get_origins') - number = fields.Char('Number', size=None, select=True, readonly=True, + number = fields.Char( + "Number", readonly=True, help="The main identifier for the shipment.") received_by = employee_field("Received By") done_by = employee_field("Done By") @@ -1730,8 +1768,17 @@ class ShipmentOutReturn(ShipmentMixin, Workflow, ModelSQL, ModelView): @classmethod def __setup__(cls): + cls.number.search_unaccented = False + cls.reference.search_unaccented = False super(ShipmentOutReturn, cls).__setup__() - cls.create_date.select = True + t = cls.__table__() + cls._sql_indexes.update({ + Index(t, (t.reference, Index.Similarity())), + Index( + t, + (t.state, Index.Equality()), + where=t.state.in_(['draft', 'received'])), + }) cls._order = [ ('effective_date', 'ASC NULLS LAST'), ('id', 'ASC'), @@ -2090,9 +2137,11 @@ class ShipmentInternal(ShipmentAssignMixin, Workflow, ModelSQL, ModelView): 'readonly': ~Eval('state').in_(['request', 'draft']), }, help="The company the shipment is associated with.") - number = fields.Char('Number', size=None, select=True, readonly=True, + number = fields.Char( + "Number", readonly=True, help="The main identifier for the shipment.") - reference = fields.Char("Reference", size=None, select=True, + reference = fields.Char( + "Reference", states={ 'readonly': ~Eval('state').in_(['request', 'draft']), }, @@ -2218,8 +2267,19 @@ class ShipmentInternal(ShipmentAssignMixin, Workflow, ModelSQL, ModelView): @classmethod def __setup__(cls): + cls.number.search_unaccented = False + cls.reference.search_unaccented = False super(ShipmentInternal, cls).__setup__() - cls.create_date.select = True + t = cls.__table__() + cls._sql_indexes.update({ + Index(t, (t.reference, Index.Similarity())), + Index( + t, + (t.state, Index.Equality()), + where=t.state.in_([ + 'request', 'draft', 'waiting', + 'assigned', 'shipped'])), + }) cls._order = [ ('effective_date', 'ASC NULLS LAST'), ('id', 'ASC'),