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. -->
-
-
-
-
-
diff --git a/view/create_chart_properties_form.xml b/view/create_chart_properties_form.xml
index b2932bc3a2..c4c2545ea2 100644
--- a/view/create_chart_properties_form.xml
+++ b/view/create_chart_properties_form.xml
@@ -3,11 +3,6 @@
this repository contains the full copyright notices and license terms. -->
-
-
-
-
-
diff --git a/view/product_configuration_form.xml b/view/product_configuration_form.xml
deleted file mode 100644
index 7a7b2dd568..0000000000
--- a/view/product_configuration_form.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/view/template_form.xml b/view/template_form.xml
index 6cd2c57903..2cf1db5db8 100644
--- a/view/template_form.xml
+++ b/view/template_form.xml
@@ -8,20 +8,6 @@ this repository contains the full copyright notices and license terms. -->
-
-
-
-
-
-
-
-
-
-
-
-
-
-