diff --git a/addons/account/partner.py b/addons/account/partner.py index e5ff919243a..2b9cb47bb63 100644 --- a/addons/account/partner.py +++ b/addons/account/partner.py @@ -123,22 +123,24 @@ class account_fiscal_position(osv.osv): else: delivery = partner - domain = [ - ('auto_apply', '=', True), - '|', ('vat_required', '=', False), ('vat_required', '=', partner.vat_subjected), - ] - if delivery.country_id.id: - fiscal_position_ids = self.search(cr, uid, domain + [('country_id', '=', delivery.country_id.id)], context=context, limit=1) + domains = [[('auto_apply', '=', True), ('vat_required', '=', partner.vat_subjected)]] + if partner.vat_subjected: + # Possibly allow fallback to non-VAT positions, if no VAT-required position matches + domains += [[('auto_apply', '=', True), ('vat_required', '=', False)]] + + for domain in domains: + if delivery.country_id.id: + fiscal_position_ids = self.search(cr, uid, domain + [('country_id', '=', delivery.country_id.id)], context=context, limit=1) + if fiscal_position_ids: + return fiscal_position_ids[0] + + fiscal_position_ids = self.search(cr, uid, domain + [('country_group_id.country_ids', '=', delivery.country_id.id)], context=context, limit=1) + if fiscal_position_ids: + return fiscal_position_ids[0] + + fiscal_position_ids = self.search(cr, uid, domain + [('country_id', '=', None), ('country_group_id', '=', None)], context=context, limit=1) if fiscal_position_ids: return fiscal_position_ids[0] - - fiscal_position_ids = self.search(cr, uid, domain + [('country_group_id.country_ids', '=', delivery.country_id.id)], context=context, limit=1) - if fiscal_position_ids: - return fiscal_position_ids[0] - - fiscal_position_ids = self.search(cr, uid, domain + [('country_id', '=', None), ('country_group_id', '=', None)], context=context, limit=1) - if fiscal_position_ids: - return fiscal_position_ids[0] return False class account_fiscal_position_tax(osv.osv): diff --git a/addons/account/res_config.py b/addons/account/res_config.py index 9e994f735aa..0cf32abab40 100644 --- a/addons/account/res_config.py +++ b/addons/account/res_config.py @@ -135,16 +135,33 @@ class account_config_settings(osv.osv_memory): 'company_id', 'income_currency_exchange_account_id', type='many2one', relation='account.account', - string="Gain Exchange Rate Account", - domain="[('type', '=', 'other')]"), + string="Gain Exchange Rate Account", + domain="[('type', '=', 'other'), ('company_id', '=', company_id)]]"), 'expense_currency_exchange_account_id': fields.related( 'company_id', 'expense_currency_exchange_account_id', type="many2one", relation='account.account', string="Loss Exchange Rate Account", - domain="[('type', '=', 'other')]"), + domain="[('type', '=', 'other'), ('company_id', '=', company_id)]]"), } + def _check_account_gain(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids, context=context): + if obj.income_currency_exchange_account_id.company_id and obj.company_id != obj.income_currency_exchange_account_id.company_id: + return False + return True + + def _check_account_loss(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids, context=context): + if obj.expense_currency_exchange_account_id.company_id and obj.company_id != obj.expense_currency_exchange_account_id.company_id: + return False + return True + + _constraints = [ + (_check_account_gain, 'The company of the gain exchange rate account must be the same than the company selected.', ['income_currency_exchange_account_id']), + (_check_account_loss, 'The company of the loss exchange rate account must be the same than the company selected.', ['expense_currency_exchange_account_id']), + ] + def _default_company(self, cr, uid, context=None): user = self.pool.get('res.users').browse(cr, uid, uid, context=context) return user.company_id.id diff --git a/addons/account/tests/__init__.py b/addons/account/tests/__init__.py index 152f89cdcc1..75f03b9a8be 100644 --- a/addons/account/tests/__init__.py +++ b/addons/account/tests/__init__.py @@ -2,3 +2,4 @@ from . import test_tax from . import test_search from . import test_reconciliation from . import test_account_move_closed_period +from . import test_fiscal_position diff --git a/addons/account/tests/test_fiscal_position.py b/addons/account/tests/test_fiscal_position.py new file mode 100644 index 00000000000..046b558860d --- /dev/null +++ b/addons/account/tests/test_fiscal_position.py @@ -0,0 +1,41 @@ +from openerp.tests.common import TransactionCase + +class TestFiscalPosition(TransactionCase): + """Tests for fiscal positions in auto apply (account.fiscal.position). + If a partner has a vat number, the fiscal positions with "vat_required=True" + are prefered. + """ + + def setUp(self): + super(TestFiscalPosition, self).setUp() + self.fiscal_position_model = self.registry('account.fiscal.position') + self.res_partner_model = self.registry('res.partner') + self.res_country_model = self.registry('res.country') + + def test_fiscal_position(self): + cr, uid = self.cr, self.uid + company_id = 1 + country_id = self.res_country_model.search(cr, uid, [('name', '=', 'France')])[0] + partner_id = self.res_partner_model.create(cr, uid, dict( + name="George", + vat_subjected=True, + notify_email="always", + country_id=country_id)) + fp_b2c_id = self.fiscal_position_model.create(cr, uid, dict(name="EU-VAT-FR-B2C", + auto_apply=True, + country_id=country_id, + vat_required=False, + sequence=1)) + fp_b2b_id = self.fiscal_position_model.create(cr, uid, dict(name="EU-VAT-FR-B2B", + auto_apply=True, + country_id=country_id, + vat_required=True, + sequence=2)) + res = self.fiscal_position_model.get_fiscal_position(cr, uid, company_id, partner_id) + self.assertEquals(fp_b2b_id, res, + "Fiscal position detection should pick B2B position as 1rst match") + + self.fiscal_position_model.write(cr, uid, [fp_b2b_id], {'auto_apply': False}) + res = self.fiscal_position_model.get_fiscal_position(cr, uid, company_id, partner_id) + self.assertEquals(fp_b2c_id, res, + "Fiscal position detection should pick B2C position as 1rst match") diff --git a/addons/crm/base_partner_merge.py b/addons/crm/base_partner_merge.py index 321c5caa517..7f958080ec1 100644 --- a/addons/crm/base_partner_merge.py +++ b/addons/crm/base_partner_merge.py @@ -9,6 +9,7 @@ import operator import psycopg2 import re from ast import literal_eval +from openerp.exceptions import ValidationError from openerp.tools import mute_logger # Validation Library https://pypi.python.org/pypi/validate_email/1.1 @@ -246,12 +247,12 @@ class MergePartnerAutomatic(osv.TransientModel): for record in proxy.browse(cr, openerp.SUPERUSER_ID, record_ids, context=context): try: proxy_model = self.pool[record.model] - field_type = proxy_model._columns[record.name].__class__._type + column = proxy_model._columns[record.name] except KeyError: # unknown model or field => skip continue - if field_type == 'function': + if isinstance(column, fields.function): continue for partner in src_partners: diff --git a/addons/crm/security/ir.model.access.csv b/addons/crm/security/ir.model.access.csv index 09150132f14..5030138ae9a 100644 --- a/addons/crm/security/ir.model.access.csv +++ b/addons/crm/security/ir.model.access.csv @@ -23,6 +23,6 @@ access_crm_lead_tag_manager,crm_lead_tag manager,model_crm_lead_tag,base.group_s access_crm_phonecall_category,crm_phonecall_category,model_crm_phonecall_category,base.group_user,1,0,0,0 access_crm_phonecall_category_salesman,crm_phonecall_category salesman,model_crm_phonecall_category,base.group_sale_salesman,1,1,1,0 access_crm_phonecall_category_manager,crm_phonecall_category manager,model_crm_phonecall_category,base.group_sale_manager,1,1,1,1 -access_crm_lost_reason,crm.lost.reason,model_crm_lost_reason,base.group_sale_manager,1,1,1,1 -access_crm_lost_reason,crm.lost.reason,model_crm_lost_reason,base.group_sale_salesman,1,1,1,0 -access_crm_lost_reason,crm.lost.reason,model_crm_lost_reason,base.group_user,1,0,0,0 \ No newline at end of file +access_crm_lost_reason_manager,crm.lost.reason.manager,model_crm_lost_reason,base.group_sale_manager,1,1,1,1 +access_crm_lost_reason_salesman,crm.lost.reason.salesman,model_crm_lost_reason,base.group_sale_salesman,1,1,1,0 +access_crm_lost_reason_user,crm.lost.reason.user,model_crm_lost_reason,base.group_user,1,0,0,0 diff --git a/addons/decimal_precision/decimal_precision.py b/addons/decimal_precision/decimal_precision.py index dee5dd0fe28..a33d76be9e6 100644 --- a/addons/decimal_precision/decimal_precision.py +++ b/addons/decimal_precision/decimal_precision.py @@ -48,11 +48,6 @@ class decimal_precision(orm.Model): def clear_cache(self, cr): """clear cache and update models. Notify other workers to restart their registry.""" self.precision_get.clear_cache(self) - env = openerp.api.Environment(cr, SUPERUSER_ID, {}) - for model in self.pool.values(): - for field in model._fields.values(): - if field.type == 'float': - field._setup_digits(env) RegistryManager.signal_registry_change(cr.dbname) def create(self, cr, uid, data, context=None): diff --git a/addons/event/event_view.xml b/addons/event/event_view.xml index 981e7b4db9b..eddcabf9b6b 100644 --- a/addons/event/event_view.xml +++ b/addons/event/event_view.xml @@ -287,6 +287,9 @@ +