diff --git a/CHANGELOG b/CHANGELOG index 7e5123f38c..e45199a596 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Remove accounts from products + Version 4.8.0 - 2018-04-23 * Bug fixes (see mercurial logs for details) diff --git a/__init__.py b/__init__.py index 3290452843..cc5e9d75c0 100644 --- a/__init__.py +++ b/__init__.py @@ -2,28 +2,24 @@ # this repository contains the full copyright notices and license terms. from trytond.pool import Pool -from .product import * -from .configuration import * +from . import product +from . import configuration from . import account def register(): Pool.register( - ProductConfiguration, - Category, - CategoryAccount, - CategoryCustomerTax, - CategorySupplierTax, + product.Category, + product.CategoryAccount, + product.CategoryCustomerTax, + product.CategorySupplierTax, account.CreateChartProperties, - Template, - TemplateAccount, - TemplateCustomerTax, - TemplateSupplierTax, - Product, - TemplateAccountCategory, - TemplateCategoryAll, - Configuration, - ConfigurationDefaultAccount, + product.Template, + product.Product, + product.TemplateAccountCategory, + product.TemplateCategoryAll, + configuration.Configuration, + configuration.ConfigurationDefaultAccount, module='account_product', type_='model') Pool.register( account.CreateChart, diff --git a/account.py b/account.py index 1cb4e50b12..2fad19e3c0 100644 --- a/account.py +++ b/account.py @@ -12,20 +12,6 @@ class CreateChartProperties: __metaclass__ = PoolMeta __name__ = 'account.create_chart.properties' - product_account_expense = fields.Many2One( - 'account.account', 'Default Expense Account', - domain=[ - ('kind', '=', 'expense'), - ('company', '=', Eval('company')), - ], - depends=['company']) - product_account_revenue = fields.Many2One( - 'account.account', 'Default Revenue Account', - domain=[ - ('kind', '=', 'revenue'), - ('company', '=', Eval('company')), - ], - depends=['company']) category_account_expense = fields.Many2One( 'account.account', 'Default Expense Account', domain=[ @@ -53,8 +39,9 @@ class CreateChart: with Transaction().set_context(company=self.properties.company.id): config = Configuration(1) - for name in ['product_account_expense', 'product_account_revenue', - 'category_account_expense', 'category_account_revenue']: + for name in [ + 'category_account_expense', + 'category_account_revenue']: setattr(config, 'default_%s' % name, getattr(self.properties, name, None)) config.save() diff --git a/configuration.py b/configuration.py index 886a6905bb..e94119aa1a 100644 --- a/configuration.py +++ b/configuration.py @@ -3,29 +3,15 @@ from trytond.pool import PoolMeta, Pool from trytond.model import fields from trytond.pyson import Eval -from trytond import backend -__all__ = ['Configuration', 'ConfigurationDefaultAccount', - 'ProductConfiguration'] +__all__ = ['Configuration', 'ConfigurationDefaultAccount'] class Configuration: __metaclass__ = PoolMeta __name__ = 'account.configuration' - default_product_account_expense = fields.MultiValue(fields.Many2One( - 'account.account', 'Default Account Expense', - domain=[ - ('kind', '=', 'expense'), - ('company', '=', Eval('context', {}).get('company', -1)), - ])) - default_product_account_revenue = fields.MultiValue(fields.Many2One( - 'account.account', 'Default Account Revenue', - domain=[ - ('kind', '=', 'revenue'), - ('company', '=', Eval('context', {}).get('company', -1)), - ])) default_category_account_expense = fields.MultiValue(fields.Many2One( 'account.account', 'Default Account Expense', domain=[ @@ -42,9 +28,7 @@ class Configuration: @classmethod def multivalue_model(cls, field): pool = Pool() - if field in {'default_product_account_expense', - 'default_product_account_revenue', - 'default_category_account_expense', + if field in {'default_category_account_expense', 'default_category_account_revenue'}: return pool.get('account.configuration.default_account') return super(Configuration, cls).multivalue_model(field) @@ -53,20 +37,6 @@ class Configuration: 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=[ @@ -81,34 +51,3 @@ class ConfigurationDefaultAccount: ('company', '=', Eval('company', -1)), ], depends=['company']) - - -class ProductConfiguration: - __metaclass__ = PoolMeta - __name__ = 'product.configuration' - - default_accounts_category = fields.Boolean( - 'Use Category\'s accounts by default') - default_taxes_category = fields.Boolean( - 'Use Category\' taxes by default') - - @classmethod - def __register__(cls, module_name): - TableHandler = backend.get('TableHandler') - - # Migration from 3.8: rename default_account_category into - # default_accounts_category - table = TableHandler(cls, module_name) - if table.column_exist('default_account_category'): - table.column_rename( - 'default_account_category', 'default_accounts_category') - - super(ProductConfiguration, cls).__register__(module_name) - - @classmethod - def default_default_accounts_category(cls): - return False - - @classmethod - def default_default_taxes_category(cls): - return False diff --git a/configuration.xml b/configuration.xml index 7565c3dfba..0eb9b87d36 100644 --- a/configuration.xml +++ b/configuration.xml @@ -8,11 +8,5 @@ this repository contains the full copyright notices and license terms. --> configuration_form - - - product.configuration - - product_configuration_form - diff --git a/product.py b/product.py index 444e8d66f2..dfb5dd0735 100644 --- a/product.py +++ b/product.py @@ -15,13 +15,14 @@ from trytond.modules.company.model import ( __all__ = ['Category', 'CategoryAccount', 'CategoryCustomerTax', 'CategorySupplierTax', - 'Template', 'TemplateAccount', - 'TemplateCustomerTax', 'TemplateSupplierTax', - 'Product', 'account_used', 'template_property', + 'Template', 'Product', 'account_used', 'template_property', 'TemplateAccountCategory', 'TemplateCategoryAll'] -def account_used(field_name): +def account_used(field_name, field_string=None): + if field_string is None: + field_string = field_name + def decorator(func): @wraps(func) def wrapper(self): @@ -30,10 +31,10 @@ def account_used(field_name): account = self.get_account(field_name + '_used') # Allow empty values on on_change if not account and not Transaction().readonly: - field_string = ( - self.fields_get([field_name])[field_name]['string']) + field = ( + self.fields_get([field_string])[field_string]['string']) self.raise_user_error('missing_account', { - 'field': field_string, + 'field': field, 'name': self.rec_name, }) return account @@ -310,68 +311,7 @@ class Template(CompanyMultiValueMixin): account_category = fields.Many2One('product.category', 'Account Category', domain=[ ('accounting', '=', True), - ], - states={ - 'required': (Eval('accounts_category', False) - | Eval('taxes_category', False)), - }, - depends=['accounts_category', 'taxes_category']) - accounts_category = fields.Boolean('Use Category\'s accounts', - help="Check to use the accounts defined on the account category.") - 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)), - ], - states={ - 'invisible': (~Eval('context', {}).get('company') - | Eval('accounts_category')), - }, - help=("The account to use instead of the one defined on the " - "account category."), depends=['accounts_category'])) - account_revenue = fields.MultiValue(fields.Many2One('account.account', - 'Account Revenue', domain=[ - ('kind', '=', 'revenue'), - ('company', '=', Eval('context', {}).get('company', -1)), - ], - states={ - 'invisible': (~Eval('context', {}).get('company') - | Eval('accounts_category')), - }, - help=("The account to use instead of the one defined on the " - "account category."), depends=['accounts_category'])) - taxes_category = fields.Boolean('Use Category\'s Taxes', - help="Check to use the taxes defined on the account category.") - customer_taxes = fields.Many2Many('product.template-customer-account.tax', - 'product', 'tax', 'Customer Taxes', - order=[('tax.sequence', 'ASC'), ('tax.id', 'ASC')], - domain=[('parent', '=', None), ['OR', - ('group', '=', None), - ('group.kind', 'in', ['sale', 'both'])], - ], - states={ - 'invisible': (~Eval('context', {}).get('company') - | Eval('taxes_category')), - }, depends=['taxes_category'], - help="The taxes to apply when selling the product.") - supplier_taxes = fields.Many2Many('product.template-supplier-account.tax', - 'product', 'tax', 'Supplier Taxes', - order=[('tax.sequence', 'ASC'), ('tax.id', 'ASC')], - domain=[('parent', '=', None), ['OR', - ('group', '=', None), - ('group.kind', 'in', ['purchase', 'both'])], - ], - states={ - 'invisible': (~Eval('context', {}).get('company') - | Eval('taxes_category')), - }, depends=['taxes_category'], - help="The taxes to apply when purchasing the product.") - customer_taxes_used = fields.Function(fields.One2Many('account.tax', None, - 'Customer Taxes Used'), 'get_taxes') - supplier_taxes_used = fields.Function(fields.One2Many('account.tax', None, - 'Supplier Taxes Used'), 'get_taxes') + ]) @classmethod def __setup__(cls): @@ -379,169 +319,53 @@ class Template(CompanyMultiValueMixin): cls._error_messages.update({ 'missing_account': ('There is no ' '"%(field)s" defined on the product "%(name)s"'), + 'missing_taxes': ('There is no account category defined ' + 'on the product "%(name)s"'), }) - @classmethod - def __register__(cls, module_name): - TableHandler = backend.get('TableHandler') - cursor = Transaction().connection.cursor() - pool = Pool() - Category = pool.get('product.category') - sql_table = cls.__table__() - category = Category.__table__() - - table = TableHandler(cls, module_name) - category_exists = table.column_exist('category') - - # Migration from 3.8: rename account_category into accounts_category - if (table.column_exist('account_category') - and not table.column_exist('accounts_category')): - table.column_rename('account_category', 'accounts_category') - - super(Template, cls).__register__(module_name) - - # Migration from 3.8: duplicate category into account_category - if category_exists: - # Only accounting category until now - cursor.execute(*category.update([category.accounting], [True])) - cursor.execute(*sql_table.update( - [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() - Config = pool.get('product.configuration') - return Config(1).default_accounts_category - - @classmethod - def default_taxes_category(cls): - pool = Pool() - Config = pool.get('product.configuration') - return Config(1).default_taxes_category - def get_account(self, name, **pattern): - if self.accounts_category: + if self.account_category: return self.account_category.get_account(name, **pattern) - else: - return self.get_multivalue(name[:-5], **pattern) def get_taxes(self, name): - if self.taxes_category: - return [x.id for x in getattr(self.account_category, name)] - else: - return [x.id for x in getattr(self, name[:-5])] - - @fields.depends('account_category', 'account_expense') - def on_change_account_expense(self): - if not self.account_category: - if self.account_expense: - self.supplier_taxes = self.account_expense.taxes - else: - self.supplier_taxes = [] - - @fields.depends('account_category', 'account_revenue') - def on_change_account_revenue(self): - if not self.account_category: - if self.account_revenue: - self.customer_taxes = self.account_revenue.taxes - else: - self.customer_taxes = [] + if self.account_category: + return getattr(self.account_category, name) @property - @account_used('account_expense') + @account_used('account_expense', 'account_category') def account_expense_used(self): pass @property - @account_used('account_revenue') + @account_used('account_revenue', 'account_category') def account_revenue_used(self): pass + @property + def customer_taxes_used(self): + taxes = self.get_taxes('customer_taxes_used') + if taxes is None: + account = self.account_revenue_used + if account: + taxes = account.taxes + if taxes is None: + self.raise_user_error('missing_taxes', { + 'name': self.rec_name, + }) + return 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' - _table = 'product_customer_taxes_rel' - product = fields.Many2One('product.template', 'Product Template', - ondelete='CASCADE', select=True, required=True) - tax = fields.Many2One('account.tax', 'Tax', ondelete='RESTRICT', - required=True) - - -class TemplateSupplierTax(ModelSQL): - 'Product Template - Supplier Tax' - __name__ = 'product.template-supplier-account.tax' - _table = 'product_supplier_taxes_rel' - product = fields.Many2One('product.template', 'Product Template', - ondelete='CASCADE', select=True, required=True) - tax = fields.Many2One('account.tax', 'Tax', ondelete='RESTRICT', - required=True) + @property + def supplier_taxes_used(self): + taxes = self.get_taxes('supplier_taxes_used') + if taxes is None: + account = self.account_expense_used + if account: + taxes = account.taxes + if taxes is None: + self.raise_user_error('missing_taxes', { + 'name': self.rec_name, + }) + return taxes class Product: @@ -549,10 +373,8 @@ class Product: __name__ = 'product.product' account_expense_used = template_property('account_expense_used') account_revenue_used = template_property('account_revenue_used') - customer_taxes_used = fields.Function(fields.One2Many('account.tax', None, - 'Customer Taxes Used'), 'get_template') - supplier_taxes_used = fields.Function(fields.One2Many('account.tax', None, - 'Supplier Taxes Used'), 'get_template') + customer_taxes_used = template_property('customer_taxes_used') + supplier_taxes_used = template_property('supplier_taxes_used') class TemplateAccountCategory(ModelSQL): diff --git a/product.xml b/product.xml index ec2f159fa7..8e5d8ab46d 100644 --- a/product.xml +++ b/product.xml @@ -10,6 +10,31 @@ this repository contains the full copyright notices and license terms. --> category_form + + + + + + + + + + + + + + + + + + + + + + + + + product.template @@ -46,29 +71,5 @@ this repository contains the full copyright notices and license terms. --> - - - - - - - - - - - - - - - - - - diff --git a/tests/test_account_product.py b/tests/test_account_product.py index 86e4563008..94205551b8 100644 --- a/tests/test_account_product.py +++ b/tests/test_account_product.py @@ -45,34 +45,16 @@ class AccountProductTestCase(ModuleTestCase): ) template.save() - self.assertIsNone(template.account_expense) - with self.assertRaises(UserError): template.account_expense_used - # with account - template = ProductTemplate( - name='test account used', - list_price=Decimal(10), - default_uom=unit.id, - account_expense=account_expense.id, - products=[], - ) - template.save() - - self.assertEqual(template.account_expense, account_expense) - self.assertEqual(template.account_expense_used, account_expense) - # with account on category category = ProductCategory(name='test account used', account_expense=account_expense, accounting=True) category.save() - template.account_expense = None - template.accounts_category = True template.account_category = category template.save() - self.assertIsNone(template.account_expense) self.assertEqual(template.account_expense_used, account_expense) # with account on grant category @@ -84,30 +66,25 @@ class AccountProductTestCase(ModuleTestCase): category.parent = parent_category category.save() - self.assertIsNone(category.account_expense) self.assertEqual(template.account_expense_used, account_expense) self.assertEqual(category.account_expense_used, account_expense) # raise only at direct usage - templates = ProductTemplate.create([{ + categories = ProductCategory.create([{ 'name': 'test with account', - 'list_price': Decimal(10), - 'default_uom': unit.id, + 'accounting': True, 'account_expense': account_expense.id, - 'products': [], }, { 'name': 'test without account', - 'list_price': Decimal(10), - 'default_uom': unit.id, + 'accounting': True, 'account_expense': None, - 'products': [], }]) - self.assertEqual(templates[0].account_expense_used.id, + self.assertEqual(categories[0].account_expense_used.id, account_expense.id) with self.assertRaises(UserError): - templates[1].account_expense_used + categories[1].account_expense_used def suite(): diff --git a/view/configuration_form.xml b/view/configuration_form.xml index ff5389f139..a66973636f 100644 --- a/view/configuration_form.xml +++ b/view/configuration_form.xml @@ -4,11 +4,6 @@ this repository contains the full copyright notices and license terms. --> - -