diff --git a/__init__.py b/__init__.py index 559b845427..166b1bb5cd 100644 --- a/__init__.py +++ b/__init__.py @@ -16,6 +16,7 @@ def register(): Pool.register( Location, Party, + PartyLocation, ProductsByLocationsContext, LocationLeadTime, Move, @@ -38,6 +39,8 @@ def register(): Inventory, InventoryLine, Configuration, + ConfigurationSequence, + ConfigurationLocation, module='stock', type_='model') Pool.register( AssignShipmentOut, diff --git a/configuration.py b/configuration.py index 956b76e758..3d541068bc 100644 --- a/configuration.py +++ b/configuration.py @@ -1,51 +1,214 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. -from trytond.model import ModelView, ModelSQL, ModelSingleton, fields +from trytond import backend +from trytond.model import (ModelView, ModelSQL, ModelSingleton, ValueMixin, + fields) +from trytond.pool import Pool from trytond.pyson import Eval +from trytond.tools.multivalue import migrate_property +from trytond.modules.company.model import ( + CompanyMultiValueMixin, CompanyValueMixin) -__all__ = ['Configuration'] +__all__ = ['Configuration', 'ConfigurationSequence', 'ConfigurationLocation'] +sequences = ['shipment_in_sequence', 'shipment_in_return_sequence', + 'shipment_out_sequence', 'shipment_out_return_sequence', + 'shipment_internal_sequence', 'inventory_sequence'] +shipment_internal_transit = fields.Many2One( + 'stock.location', "Internal Shipment Transit", required=True, + domain=[ + ('type', '=', 'storage'), + ]) -class Configuration(ModelSingleton, ModelSQL, ModelView): +def default_func(field_name): + @classmethod + def default(cls, **pattern): + return getattr( + cls.multivalue_model(field_name), + 'default_%s' % field_name, lambda: None)() + return default + + +def default_sequence(name): + @classmethod + def default(cls): + pool = Pool() + ModelData = pool.get('ir.model.data') + return ModelData.get_id('stock', name) + return default + + +class Configuration( + ModelSingleton, ModelSQL, ModelView, CompanyMultiValueMixin): 'Stock Configuration' __name__ = 'stock.configuration' - shipment_in_sequence = fields.Property(fields.Many2One('ir.sequence', - 'Supplier Shipment Sequence', domain=[ + shipment_in_sequence = fields.MultiValue(fields.Many2One( + 'ir.sequence', "Supplier Shipment Sequence", required=True, + domain=[ ('company', 'in', [Eval('context', {}).get('company', -1), None]), ('code', '=', 'stock.shipment.in'), - ], required=True)) - shipment_in_return_sequence = fields.Property(fields.Many2One( - 'ir.sequence', 'Supplier Return Shipment Sequence', domain=[ + ])) + shipment_in_return_sequence = fields.MultiValue(fields.Many2One( + 'ir.sequence', "Supplier Return Shipment Sequence", required=True, + domain=[ ('company', 'in', [Eval('context', {}).get('company', -1), None]), ('code', '=', 'stock.shipment.in.return'), - ], required=True)) - shipment_out_sequence = fields.Property(fields.Many2One('ir.sequence', - 'Customer Shipment Sequence', domain=[ + ])) + shipment_out_sequence = fields.MultiValue(fields.Many2One( + 'ir.sequence', "Customer Shipment Sequence", required=True, + domain=[ ('company', 'in', [Eval('context', {}).get('company', -1), None]), ('code', '=', 'stock.shipment.out'), - ], required=True)) - shipment_out_return_sequence = fields.Property(fields.Many2One( - 'ir.sequence', 'Customer Return Shipment Sequence', domain=[ + ])) + shipment_out_return_sequence = fields.MultiValue(fields.Many2One( + 'ir.sequence', "Customer Return Shipment Sequence", required=True, + domain=[ ('company', 'in', [Eval('context', {}).get('company', -1), None]), ('code', '=', 'stock.shipment.out.return'), - ], required=True)) - shipment_internal_sequence = fields.Property(fields.Many2One( - 'ir.sequence', 'Internal Shipment Sequence', domain=[ + ])) + shipment_internal_sequence = fields.MultiValue(fields.Many2One( + 'ir.sequence', "Internal Shipment Sequence", required=True, + domain=[ ('company', 'in', [Eval('context', {}).get('company', -1), None]), ('code', '=', 'stock.shipment.internal'), - ], required=True)) - shipment_internal_transit = fields.Property(fields.Many2One( - 'stock.location', 'Internal Shipment Transit', domain=[ - ('type', '=', 'storage'), - ], required=True)) - inventory_sequence = fields.Property(fields.Many2One( - 'ir.sequence', 'Inventory Sequence', domain=[ + ])) + inventory_sequence = fields.MultiValue(fields.Many2One( + 'ir.sequence', "Inventory Sequence", required=True, + domain=[ ('company', 'in', [Eval('context', {}).get('company', -1), None]), ('code', '=', 'stock.inventory'), - ], required=True)) + ])) + shipment_internal_transit = fields.MultiValue(shipment_internal_transit) + + @classmethod + def multivalue_model(cls, field): + pool = Pool() + if field in sequences: + return pool.get('stock.configuration.sequence') + if field == 'shipment_internal_transit': + return pool.get('stock.configuration.location') + return super(Configuration, cls).multivalue_model(field) + + default_shipment_in_sequence = default_func('shipment_in_sequence') + default_shipment_in_return_sequence = default_func( + 'shipment_in_return_sequence') + default_shipment_out_sequence = default_func('shipment_out_sequence') + default_shipment_out_return_sequence = default_func( + 'shipment_out_return_sequence') + default_shipment_internal_sequence = default_func( + 'shipment_internal_sequence') + default_inventory_sequence = default_func('inventory_sequence') + default_shipment_internal_transit = default_func( + 'shipment_internal_transit') + + +class ConfigurationSequence(ModelSQL, CompanyValueMixin): + "Stock Configuration Sequence" + __name__ = 'stock.configuration.sequence' + shipment_in_sequence = fields.Many2One( + 'ir.sequence', "Supplier Shipment Sequence", required=True, + domain=[ + ('company', 'in', [Eval('company', -1), None]), + ('code', '=', 'stock.shipment.in'), + ], + depends=['company']) + shipment_in_return_sequence = fields.Many2One( + 'ir.sequence', "Supplier Return Shipment Sequence", required=True, + domain=[ + ('company', 'in', [Eval('company', -1), None]), + ('code', '=', 'stock.shipment.in.return'), + ], + depends=['company']) + shipment_out_sequence = fields.Many2One( + 'ir.sequence', "Customer Shipment Sequence", required=True, + domain=[ + ('company', 'in', [Eval('company', -1), None]), + ('code', '=', 'stock.shipment.out'), + ], + depends=['company']) + shipment_out_return_sequence = fields.Many2One( + 'ir.sequence', "Customer Return Shipment Sequence", required=True, + domain=[ + ('company', 'in', [Eval('company', -1), None]), + ('code', '=', 'stock.shipment.out.return'), + ], + depends=['company']) + shipment_internal_sequence = fields.Many2One( + 'ir.sequence', "Internal Shipment Sequence", required=True, + domain=[ + ('company', 'in', [Eval('company', -1), None]), + ('code', '=', 'stock.shipment.internal'), + ], + depends=['company']) + inventory_sequence = fields.Many2One( + 'ir.sequence', "Inventory Sequence", required=True, + domain=[ + ('company', 'in', [Eval('company', -1), None]), + ('code', '=', 'stock.inventory'), + ], + depends=['company']) + + @classmethod + def __register__(cls, module_name): + TableHandler = backend.get('TableHandler') + exist = TableHandler.table_exist(cls._table) + + super(ConfigurationSequence, cls).__register__(module_name) + + if not exist: + cls._migrate_property([], [], []) + + @classmethod + def _migrate_property(cls, field_names, value_names, fields): + field_names.extend(sequences) + value_names.extend(sequences) + fields.append('company') + migrate_property( + 'stock.configuration', field_names, cls, value_names, + fields=fields) + + default_shipment_in_sequence = default_sequence('sequence_shipment_in') + default_shipment_in_return_sequence = default_sequence( + 'sequence_shipment_in_return') + default_shipment_out_sequence = default_sequence('sequence_shipment_out') + default_shipment_out_return_sequence = default_sequence( + 'sequence_shipment_out_return') + default_shipment_internal_sequence = default_sequence( + 'sequence_shipment_internal') + default_inventory_sequence = default_sequence('sequence_inventory') + + +class ConfigurationLocation(ModelSQL, ValueMixin): + "Stock Configuration Location" + __name__ = 'stock.configuration.location' + shipment_internal_transit = shipment_internal_transit + + @classmethod + def __register__(cls, module_name): + TableHandler = backend.get('TableHandler') + exist = TableHandler.table_exist(cls._table) + + super(ConfigurationLocation, cls).__register__(module_name) + + if not exist: + cls._migrate_property([], [], []) + + @classmethod + def _migrate_property(cls, field_names, value_names, fields): + field_names.append('shipment_internal_transit') + value_names.append('shipment_internal_transit') + migrate_property( + 'stock.configuration', field_names, cls, value_names, + fields=fields) + + @classmethod + def default_shipment_internal_transit(cls): + pool = Pool() + ModelData = pool.get('ir.model.data') + return ModelData.get_id('stock', 'location_transit') diff --git a/configuration.xml b/configuration.xml index bf9a307ce0..02ff9c09f4 100644 --- a/configuration.xml +++ b/configuration.xml @@ -40,44 +40,4 @@ this repository contains the full copyright notices and license terms. --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/location.py b/location.py index 0a3b2194b8..f4aa88c35c 100644 --- a/location.py +++ b/location.py @@ -3,15 +3,16 @@ import datetime from decimal import Decimal -from trytond.model import ModelView, ModelSQL, MatchMixin, fields, \ - sequence_ordered +from trytond.model import (ModelView, ModelSQL, MatchMixin, ValueMixin, fields, + sequence_ordered) from trytond import backend from trytond.pyson import Eval, If from trytond.transaction import Transaction from trytond.pool import Pool, PoolMeta from trytond.tools import grouped_slice +from trytond.tools.multivalue import migrate_property -__all__ = ['Location', 'Party', 'ProductsByLocationsContext', +__all__ = ['Location', 'Party', 'PartyLocation', 'ProductsByLocationsContext', 'LocationLeadTime'] STATES = { @@ -396,17 +397,78 @@ class Location(ModelSQL, ModelView): return res +supplier_location = fields.Many2One( + 'stock.location', "Supplier Location", domain=[('type', '=', 'supplier')], + help='The default source location when receiving products from the party.') +customer_location = fields.Many2One( + 'stock.location', "Customer Location", domain=[('type', '=', 'customer')], + help='The default destination location when sending products to the party.' + ) + + class Party: __metaclass__ = PoolMeta __name__ = 'party.party' - supplier_location = fields.Property(fields.Many2One('stock.location', - 'Supplier Location', domain=[('type', '=', 'supplier')], - help='The default source location when receiving products from the ' - 'party.')) - customer_location = fields.Property(fields.Many2One('stock.location', - 'Customer Location', domain=[('type', '=', 'customer')], - help='The default destination location when sending products to the ' - 'party.')) + supplier_location = fields.MultiValue(supplier_location) + customer_location = fields.MultiValue(customer_location) + locations = fields.One2Many( + 'party.party.location', 'party', "Locations") + + @classmethod + def multivalue_model(cls, field): + pool = Pool() + if field in {'supplier_location', 'customer_location'}: + return pool.get('party.party.location') + return super(Party, cls).multivalue_model(field) + + @classmethod + def default_supplier_location(cls, **pattern): + return cls.multivalue_model( + 'supplier_location').default_supplier_location() + + @classmethod + def default_customer_location(cls, **pattern): + return cls.multivalue_model( + 'customer_location').default_customer_location() + + +class PartyLocation(ModelSQL, ValueMixin): + "Party Location" + __name__ = 'party.party.location' + party = fields.Many2One( + 'party.party', "Party", ondelete='CASCADE', select=True) + supplier_location = supplier_location + customer_location = customer_location + + @classmethod + def __register__(cls, module_name): + TableHandler = backend.get('TableHandler') + exist = TableHandler.table_exist(cls._table) + + super(PartyLocation, cls).__register__(module_name) + + if not exist: + cls._migrate_property([], [], []) + + @classmethod + def _migrate_property(cls, field_names, value_names, fields): + field_names.extend(['supplier_location', 'customer_location']) + value_names.extend(['supplier_location', 'customer_location']) + migrate_property( + 'party.party', field_names, cls, value_names, + parent='party', fields=fields) + + @classmethod + def default_supplier_location(cls): + pool = Pool() + ModelData = pool.get('ir.model.data') + return ModelData.get_id('stock', 'location_supplier') + + @classmethod + def default_customer_location(cls): + pool = Pool() + ModelData = pool.get('ir.model.data') + return ModelData.get_id('stock', 'location_customer') class ProductsByLocationsContext(ModelView): diff --git a/location.xml b/location.xml index ed7fbaac09..dd3edd616c 100644 --- a/location.xml +++ b/location.xml @@ -215,25 +215,5 @@ this repository contains the full copyright notices and license terms. --> Transit storage - - - - - - - - - - - - - - diff --git a/shipment.py b/shipment.py index 8e59e65900..e3945a6fea 100644 --- a/shipment.py +++ b/shipment.py @@ -2165,7 +2165,7 @@ class ShipmentInternal(Workflow, ModelSQL, ModelView): pool = Pool() Config = pool.get('stock.configuration') if self.planned_date != self.planned_start_date: - return Config(1).shipment_internal_transit.id + return Config(1).get_multivalue('shipment_internal_transit').id @fields.depends('planned_date', 'from_location', 'to_location') def on_change_with_planned_start_date(self, pattern=None):