diff --git a/__init__.py b/__init__.py index f2611cbc07..f74314ef54 100644 --- a/__init__.py +++ b/__init__.py @@ -10,11 +10,14 @@ def register(): Pool.register( ProductConfiguration, Category, + CategoryAccount, CategoryCustomerTax, CategorySupplierTax, Template, + TemplateAccount, TemplateCustomerTax, TemplateSupplierTax, Product, Configuration, + ConfigurationDefaultAccount, module='account_product', type_='model') diff --git a/configuration.py b/configuration.py index 83b62e8407..e17306226e 100644 --- a/configuration.py +++ b/configuration.py @@ -6,61 +6,81 @@ from trytond.pyson import Eval from trytond import backend -__all__ = ['Configuration', 'ProductConfiguration'] +__all__ = ['Configuration', 'ConfigurationDefaultAccount', + 'ProductConfiguration'] class Configuration: __metaclass__ = PoolMeta __name__ = 'account.configuration' - default_product_account_expense = fields.Function(fields.Many2One( + default_product_account_expense = fields.MultiValue(fields.Many2One( 'account.account', 'Default Account Expense', domain=[ ('kind', '=', 'expense'), ('company', '=', Eval('context', {}).get('company', -1)), - ]), - 'get_account', setter='set_account') - default_product_account_revenue = fields.Function(fields.Many2One( + ])) + default_product_account_revenue = fields.MultiValue(fields.Many2One( 'account.account', 'Default Account Revenue', domain=[ ('kind', '=', 'revenue'), ('company', '=', Eval('context', {}).get('company', -1)), - ]), - 'get_account', setter='set_account') - default_category_account_expense = fields.Function(fields.Many2One( + ])) + default_category_account_expense = fields.MultiValue(fields.Many2One( 'account.account', 'Default Account Expense', domain=[ ('kind', '=', 'expense'), ('company', '=', Eval('context', {}).get('company', -1)), - ]), - 'get_account', setter='set_account') - default_category_account_revenue = fields.Function(fields.Many2One( + ])) + default_category_account_revenue = fields.MultiValue(fields.Many2One( 'account.account', 'Default Account Revenue', domain=[ ('kind', '=', 'revenue'), ('company', '=', Eval('context', {}).get('company', -1)), - ]), - 'get_account', setter='set_account') + ])) @classmethod - def _get_account_field(cls, name): + def multivalue_model(cls, field): pool = Pool() - ModelField = pool.get('ir.model.field') - if name in ['default_product_account_expense', - 'default_product_account_revenue']: - field, = ModelField.search([ - ('model.model', '=', 'product.template'), - ('name', '=', name[len('default_product_'):]), - ], limit=1) - return field - elif name in ['default_category_account_expense', - 'default_category_account_revenue']: - field, = ModelField.search([ - ('model.model', '=', 'product.category'), - ('name', '=', name[len('default_category_'):]), - ], limit=1) - return field - return super(Configuration, cls)._get_account_field(name) + if field in {'default_product_account_expense', + 'default_product_account_revenue', + 'default_category_account_expense', + 'default_category_account_revenue'}: + return pool.get('account.configuration.default_account') + return super(Configuration, cls).multivalue_model(field) + + +class ConfigurationDefaultAccount: + __metaclass__ = PoolMeta + __name__ = 'account.configuration.default_account' + default_product_account_expense = fields.Many2One( + 'account.account', "Default Account Expense", + domain=[ + ('kind', '=', 'expense'), + ('company', '=', Eval('company', -1)), + ], + depends=['company']) + default_product_account_revenue = fields.Many2One( + 'account.account', "Default Account Revenue", + domain=[ + ('kind', '=', 'revenue'), + ('company', '=', Eval('company', -1)), + ], + depends=['company']) + default_category_account_expense = fields.Many2One( + 'account.account', "Default Account Expense", + domain=[ + ('kind', '=', 'expense'), + ('company', '=', Eval('company', -1)), + ], + depends=['company']) + default_category_account_revenue = fields.Many2One( + 'account.account', "Default Account Revenue", + domain=[ + ('kind', '=', 'revenue'), + ('company', '=', Eval('company', -1)), + ], + depends=['company']) class ProductConfiguration: diff --git a/product.py b/product.py index 52c6b6c178..722148d8b7 100644 --- a/product.py +++ b/product.py @@ -7,10 +7,15 @@ from trytond.pyson import Eval, Or, Bool from trytond import backend from trytond.pool import PoolMeta, Pool from trytond.transaction import Transaction +from trytond.tools.multivalue import migrate_property +from trytond.modules.company.model import ( + CompanyMultiValueMixin, CompanyValueMixin) -__all__ = ['Category', 'CategoryCustomerTax', 'CategorySupplierTax', - 'Template', 'TemplateCustomerTax', 'TemplateSupplierTax', 'Product', - 'MissingFunction'] +__all__ = ['Category', 'CategoryAccount', + 'CategoryCustomerTax', 'CategorySupplierTax', + 'Template', 'TemplateAccount', + 'TemplateCustomerTax', 'TemplateSupplierTax', + 'Product', 'MissingFunction'] class MissingFunction(fields.Function): @@ -38,7 +43,7 @@ class MissingFunction(fields.Function): return value -class Category: +class Category(CompanyMultiValueMixin): __metaclass__ = PoolMeta __name__ = 'product.category' accounting = fields.Boolean('Accounting', select=True, @@ -53,7 +58,9 @@ class Category: }, depends=['accounting'], help="Use the accounts defined on the parent category.") - account_expense = fields.Property(fields.Many2One('account.account', + accounts = fields.One2Many( + 'product.category.account', 'category', "Accounts") + account_expense = fields.MultiValue(fields.Many2One('account.account', 'Account Expense', domain=[ ('kind', '=', 'expense'), ('company', '=', Eval('context', {}).get('company', -1)), @@ -64,7 +71,7 @@ class Category: | ~Eval('accounting', False)), }, depends=['account_parent', 'accounting'])) - account_revenue = fields.Property(fields.Many2One('account.account', + account_revenue = fields.MultiValue(fields.Many2One('account.account', 'Account Revenue', domain=[ ('kind', '=', 'revenue'), ('company', '=', Eval('context', {}).get('company', -1)), @@ -135,18 +142,42 @@ class Category: Eval('account_parent', False) | Eval('taxes_parent', False)) cls.parent.depends.extend(['account_parent', 'taxes_parent']) + @classmethod + def multivalue_model(cls, field): + pool = Pool() + if field in {'account_expense', 'account_revenue'}: + return pool.get('product.category.account') + return super(Category, cls).multivalue_model(field) + @classmethod def default_accounting(cls): return False - def get_account(self, name): - if self.account_parent: - # Use __getattr__ to avoid raise of exception - account = self.parent.__getattr__(name) - else: - account = getattr(self, name[:-5]) + @classmethod + def default_account_expense(cls, **pattern): + pool = Pool() + Configuration = pool.get('account.configuration') + config = Configuration(1) + account = config.get_multivalue( + 'default_category_account_expense', **pattern) return account.id if account else None + @classmethod + def default_account_revenue(cls, **pattern): + pool = Pool() + Configuration = pool.get('account.configuration') + config = Configuration(1) + account = config.get_multivalue( + 'default_category_account_revenue', **pattern) + return account.id if account else None + + def get_account(self, name, **pattern): + if self.account_parent: + return self.parent.get_account(name, **pattern) + else: + account = self.get_multivalue(name[:-5], **pattern) + return account.id if account else None + def get_taxes(self, name): if self.taxes_parent: return [x.id for x in getattr(self.parent, name)] @@ -182,6 +213,46 @@ class Category: ] +class CategoryAccount(ModelSQL, CompanyValueMixin): + "Category Account" + __name__ = 'product.category.account' + category = fields.Many2One( + 'product.category', "Category", ondelete='CASCADE', select=True) + account_expense = fields.Many2One( + 'account.account', "Account Expense", + domain=[ + ('kind', '=', 'expense'), + ('company', '=', Eval('company', -1)), + ], + depends=['company']) + account_revenue = fields.Many2One( + 'account.account', "Account Revenue", + domain=[ + ('kind', '=', 'revenue'), + ('company', '=', Eval('company', -1)), + ], + depends=['company']) + + @classmethod + def __register__(cls, module_name): + TableHandler = backend.get('TableHandler') + exist = TableHandler.table_exist(cls._table) + + super(CategoryAccount, cls).__register__(module_name) + + if not exist: + cls._migrate_property([], [], []) + + @classmethod + def _migrate_property(cls, field_names, value_names, fields): + field_names.extend(['account_expense', 'account_revenue']) + value_names.extend(['account_expense', 'account_revenue']) + fields.append('company') + migrate_property( + 'product.category', field_names, cls, value_names, + parent='category', fields=fields) + + class CategoryCustomerTax(ModelSQL): 'Category - Customer Tax' __name__ = 'product.category-customer-account.tax' @@ -224,7 +295,7 @@ class CategorySupplierTax(ModelSQL): super(CategorySupplierTax, cls).__register__(module_name) -class Template: +class Template(CompanyMultiValueMixin): __metaclass__ = PoolMeta __name__ = 'product.template' account_category = fields.Many2One('product.category', 'Account Category', @@ -238,7 +309,9 @@ class Template: depends=['accounts_category', 'taxes_category']) accounts_category = fields.Boolean('Use Category\'s accounts', help="Check to use the accounts defined on the account category.") - account_expense = fields.Property(fields.Many2One('account.account', + accounts = fields.One2Many( + 'product.template.account', 'template', "Accounts") + account_expense = fields.MultiValue(fields.Many2One('account.account', 'Account Expense', domain=[ ('kind', '=', 'expense'), ('company', '=', Eval('context', {}).get('company', -1)), @@ -249,7 +322,7 @@ class Template: }, help=("The account to use instead of the one defined on the " "account category."), depends=['accounts_category'])) - account_revenue = fields.Property(fields.Many2One('account.account', + account_revenue = fields.MultiValue(fields.Many2One('account.account', 'Account Revenue', domain=[ ('kind', '=', 'revenue'), ('company', '=', Eval('context', {}).get('company', -1)), @@ -330,6 +403,31 @@ class Template: [sql_table.account_category], [sql_table.category])) + @classmethod + def multivalue_model(cls, field): + pool = Pool() + if field in {'account_expense', 'account_revenue'}: + return pool.get('product.template.account') + return super(Template, cls).multivalue_model(field) + + @classmethod + def default_account_expense(cls, **pattern): + pool = Pool() + Configuration = pool.get('account.configuration') + config = Configuration(1) + account = config.get_multivalue( + 'default_product_account_expense', **pattern) + return account.id if account else None + + @classmethod + def default_account_revenue(cls, **pattern): + pool = Pool() + Configuration = pool.get('account.configuration') + config = Configuration(1) + account = config.get_multivalue( + 'default_product_account_revenue', **pattern) + return account.id if account else None + @classmethod def default_accounts_category(cls): pool = Pool() @@ -342,12 +440,12 @@ class Template: Config = pool.get('product.configuration') return Config(1).default_taxes_category - def get_account(self, name): + def get_account(self, name, **pattern): if self.accounts_category: - account = self.account_category.__getattr__(name) + return self.account_category.get_account(name, **pattern) else: - account = getattr(self, name[:-5]) - return account.id if account else None + account = self.get_multivalue(name[:-5], **pattern) + return account.id if account else None def get_taxes(self, name): if self.taxes_category: @@ -372,6 +470,46 @@ class Template: self.customer_taxes = [] +class TemplateAccount(ModelSQL, CompanyValueMixin): + "Product Template Account" + __name__ = 'product.template.account' + template = fields.Many2One( + 'product.template', "Template", ondelete='CASCADE', select=True) + account_expense = fields.Many2One( + 'account.account', "Account Expense", + domain=[ + ('kind', '=', 'expense'), + ('company', '=', Eval('company', -1)), + ], + depends=['company']) + account_revenue = fields.Many2One( + 'account.account', "Account Revenue", + domain=[ + ('kind', '=', 'revenue'), + ('company', '=', Eval('company', -1)), + ], + depends=['company']) + + @classmethod + def __register__(cls, module_name): + TableHandler = backend.get('TableHandler') + exist = TableHandler.table_exist(cls._table) + + super(TemplateAccount, cls).__register__(module_name) + + if not exist: + cls._migrate_property([], [], []) + + @classmethod + def _migrate_property(cls, field_names, value_names, fields): + field_names.extend(['account_expense', 'account_revenue']) + value_names.extend(['account_expense', 'account_revenue']) + fields.append('company') + migrate_property( + 'product.template', field_names, cls, value_names, + parent='template', fields=fields) + + class TemplateCustomerTax(ModelSQL): 'Product Template - Customer Tax' __name__ = 'product.template-customer-account.tax'