# 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 ModelSQL, fields from trytond.modules.company.model import CompanyValueMixin from trytond.modules.product.product import TemplateFunction from trytond.pool import Pool, PoolMeta from trytond.pyson import Eval from trytond.transaction import Transaction cost_price_warehouse = fields.Boolean( "Cost Price per Warehouse", help="Compute product cost price for each warehouse.") class Configuration(metaclass=PoolMeta): __name__ = 'product.configuration' cost_price_warehouse = fields.MultiValue(cost_price_warehouse) @classmethod def default_cost_price_warehouse(cls, **pattern): return cls.multivalue_model( 'cost_price_warehouse').default_cost_price_warehouse() class ConfigurationCostPriceWarehouse(ModelSQL, CompanyValueMixin): __name__ = 'product.configuration.cost_price_warehouse' cost_price_warehouse = cost_price_warehouse @classmethod def default_cost_price_warehouse(cls): return False class Product(metaclass=PoolMeta): __name__ = 'product.product' @classmethod def __setup__(cls): super().__setup__() readonly = ( Eval('context', {}).get('cost_price_warehouse', False) & ~Eval('context', {}).get('warehouse')) if cls.cost_price.states['readonly']: cls.cost_price.states['readonly'] |= readonly else: cls.cost_price.states['readonly'] = readonly def multivalue_records(self, field): Value = self.multivalue_model(field) records = super().multivalue_records(field) if issubclass(Value, CostPrice): # Sort to get record with empty warehouse at the end records = sorted(records, key=lambda r: r.warehouse is None) return records def get_multivalue(self, name, **pattern): pool = Pool() Company = pool.get('company.company') context = Transaction().context if not isinstance(self._fields[name], TemplateFunction): Value = self.multivalue_model(name) if issubclass(Value, CostPrice) and context.get('company'): company = Company(context['company']) if company.cost_price_warehouse: pattern.setdefault('warehouse', context.get('warehouse')) return super().get_multivalue(name, **pattern) def set_multivalue(self, name, value, save=True, **pattern): pool = Pool() Company = pool.get('company.company') context = Transaction().context Value = self.multivalue_model(name) if issubclass(Value, CostPrice) and context.get('company'): company = Company(context['company']) if company.cost_price_warehouse: pattern.setdefault('warehouse', context.get('warehouse')) if not value and not pattern.get('warehouse'): return [] return super().set_multivalue(name, value, save=save, **pattern) @classmethod def _domain_moves_cost(cls): pool = Pool() Company = pool.get('company.company') context = Transaction().context domain = super()._domain_moves_cost() if context.get('company'): company = Company(context['company']) if company.cost_price_warehouse: warehouse = context.get('warehouse') domain = [ domain, ['OR', ('from_location', 'child_of', warehouse, 'parent'), ('from_location.cost_warehouse', '=', warehouse), ('to_location', 'child_of', warehouse, 'parent'), ('to_location.cost_warehouse', '=', warehouse), ], ] return domain @classmethod def _domain_in_moves_cost(cls): pool = Pool() Company = pool.get('company.company') context = Transaction().context domain = super()._domain_in_moves_cost() if context.get('company'): company = Company(context['company']) if company.cost_price_warehouse: warehouse = context.get('warehouse') domain = ['OR', domain, [ ('from_location.type', '=', 'storage'), ('to_location.type', '=', 'storage'), ('from_location', 'not child_of', warehouse, 'parent'), ['OR', ('from_location.cost_warehouse', '!=', warehouse), ('from_location.cost_warehouse', '=', None), ], ['OR', ('to_location', 'child_of', warehouse, 'parent'), ('to_location.cost_warehouse', '=', warehouse), ], ] ] return domain @classmethod def _domain_out_moves_cost(cls): pool = Pool() Company = pool.get('company.company') context = Transaction().context domain = super()._domain_out_moves_cost() if context.get('company'): company = Company(context['company']) if company.cost_price_warehouse: warehouse = context.get('warehouse') domain = ['OR', domain, [ ('from_location.type', '=', 'storage'), ('to_location.type', '=', 'storage'), ('to_location', 'not child_of', warehouse, 'parent'), ['OR', ('to_location.cost_warehouse', '!=', warehouse), ('to_location.cost_warehouse', '=', None), ], ['OR', ('from_location', 'child_of', warehouse, 'parent'), ('from_location.cost_warehouse', '=', warehouse), ], ] ] return domain @classmethod def _domain_storage_quantity(cls): pool = Pool() Company = pool.get('company.company') context = Transaction().context domain = super()._domain_storage_quantity() if context.get('company'): company = Company(context['company']) if company.cost_price_warehouse: warehouse = context.get('warehouse') domain = [ domain, ['OR', ('parent', 'child_of', warehouse), ('cost_warehouse', '=', warehouse), ], ] return domain @classmethod def default_cost_price(cls, **pattern): context = Transaction().context default = super().default_cost_price() if (context.get('cost_price_warehouse') and not pattern.get('warehouse', context.get('warehouse'))): default = None return default class CostPrice(metaclass=PoolMeta): __name__ = 'product.cost_price' warehouse = fields.Many2One( 'stock.location', "Warehouse", ondelete='RESTRICT', domain=[ ('type', '=', 'warehouse'), ], states={ 'required': Eval('warehouse_required', False), }) warehouse_required = fields.Function(fields.Boolean( "Warehouse Required"), 'get_warehouse_required') @classmethod def get_warehouse_required(cls, records, name): return {r.id: r.company.cost_price_warehouse for r in records} class CostPriceRevision(metaclass=PoolMeta): __name__ = 'product.cost_price.revision' warehouse = fields.Many2One( 'stock.location', "Warehouse", ondelete='RESTRICT', domain=[ ('type', '=', 'warehouse'), ], states={ 'required': Eval('warehouse_required', False), }) warehouse_required = fields.Function(fields.Boolean( "Warehouse Required"), 'get_warehouse_required') @classmethod def default_warehouse(cls): pool = Pool() Company = pool.get('company.company') company_id = cls.default_company() if company_id is not None and company_id >= 0: company = Company(company_id) if company.cost_price_warehouse: return Transaction().context.get('warehouse') @classmethod def get_warehouse_required(cls, records, name): return {r.id: r.company.cost_price_warehouse for r in records} @classmethod def _get_for_product_domain(cls): pool = Pool() Company = pool.get('company.company') domain = super()._get_for_product_domain() context = Transaction().context if context.get('company'): company = Company(context['company']) if company.cost_price_warehouse: domain = [ domain, ('warehouse', '=', context.get('warehouse')), ] return domain class ModifyCostPrice(metaclass=PoolMeta): __name__ = 'product.modify_cost_price' def get_revision(self, Revision): revision = super().get_revision(Revision) if revision.company.cost_price_warehouse: revision.warehouse = Transaction().context.get('warehouse') return revision class ProductCostHistory(metaclass=PoolMeta): __name__ = 'product.product.cost_history' @classmethod def _non_moves_clause(cls, history_table, user): clause = super()._non_moves_clause(history_table, user) if user.company and user.company.cost_price_warehouse: warehouse_id = user.warehouse.id if user.warehouse else None clause &= history_table.warehouse == warehouse_id return clause