diff --git a/account_partner_required/README.rst b/account_partner_required/README.rst new file mode 100644 index 00000000..dd3f5b7f --- /dev/null +++ b/account_partner_required/README.rst @@ -0,0 +1,68 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +======================== +Account Partner Required +======================== + +This module adds an option *Partner policy* on account types. + +You have the choice between 3 policies: + +* *optional* (the default policy): partner is optional, +* *always*: require a partner, +* *never*: forbid a partner. + +This module is useful to enforce a partner on account move lines on +customer and supplier accounts. + +This module is very similar to the module *account_analytic_required* available in the OCA project `account-analytic `_. + +Configuration +============= + +Go to the menu *Accounting > Configuration > Accounting > Account Types* and edit each account types to configure the correct *Partner policy*. + +Usage +===== + +If you put a partner on an account move line with an account whose type is configured with *Partner policy* = *never*, you will get an error message. + +If you don't put a partner on an account move line with an account whose type is configured with *Partner policy* = *always*, you will get an error message. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/92/10.0 + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Stéphane Bidoul +* Alexis de Lattre + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/account_partner_required/__init__.py b/account_partner_required/__init__.py index 5cb88930..cde864ba 100644 --- a/account_partner_required/__init__.py +++ b/account_partner_required/__init__.py @@ -1,23 +1,3 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Account partner required module for OpenERP -# Copyright (C) 2014 Acsone (http://acsone.eu). -# @author Stéphane Bidoul -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## +# -*- coding: utf-8 -*- -from . import account +from . import models diff --git a/account_partner_required/__manifest__.py b/account_partner_required/__manifest__.py index d50d5752..fa9ba307 100644 --- a/account_partner_required/__manifest__.py +++ b/account_partner_required/__manifest__.py @@ -1,46 +1,19 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Account partner required module for OpenERP -# Copyright (C) 2014 Acsone (http://acsone.eu). -# @author Stéphane Bidoul -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## +# -*- coding: utf-8 -*- +# © 2014-2016 Acsone (http://acsone.eu). +# © 2016 Akretion (http://www.akretion.com/) +# @author Stéphane Bidoul +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { 'name': 'Account partner required', - 'version': '8.0.0.1.0', - 'category': 'Generic Modules/Accounting', + 'version': '10.0.1.0.0', + 'category': 'Accounting', 'license': 'AGPL-3', - 'description': """This module adds an option "partner policy" -on account types. - -You have the choice between 3 policies : optional (the default), -always (require a partner), and never (forbid a partner). - -This module is useful to enforce a partner on account move lines on -customer and supplier accounts. - -Module developed by Stéphane Bidoul , -inspired by Alexis de Lattre 's -account_analytic_required module. -""", - 'author': "ACSONE SA/NV,Odoo Community Association (OCA)", + 'summary': "Adds an option 'partner policy' on account types", + 'author': "ACSONE SA/NV,Akretion,Odoo Community Association (OCA)", 'website': 'http://acsone.eu/', - 'depends': ['account'], - 'data': ['account_view.xml'], - 'installable': False, + 'depends': ['account_type_menu'], + 'data': ['views/account.xml'], + 'installable': True, } diff --git a/account_partner_required/account.py b/account_partner_required/account.py deleted file mode 100644 index 92af74fa..00000000 --- a/account_partner_required/account.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Account partner required module for OpenERP -# Copyright (C) 2014 Acsone (http://acsone.eu). -# @author Stéphane Bidoul -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import orm, fields -from openerp.tools.translate import _ - - -class account_account_type(orm.Model): - _inherit = "account.account.type" - - def _get_policies(self, cr, uid, context=None): - """This is the method to be inherited for adding policies""" - return [('optional', _('Optional')), - ('always', _('Always')), - ('never', _('Never'))] - - _columns = { - 'partner_policy': fields.selection( - lambda self, *args, **kwargs: self._get_policies(*args, **kwargs), - 'Policy for partner field', - required=True, - help="Set the policy for the partner field : if you select " - "'Optional', the accountant is free to put a partner " - "on an account move line with this type of account ; " - "if you select 'Always', the accountant will get an error " - "message if there is no partner ; if you select 'Never', " - "the accountant will get an error message if a partner " - "is present."), - } - - _defaults = { - 'partner_policy': 'optional', - } - - -class account_move_line(orm.Model): - _inherit = "account.move.line" - - def _get_partner_policy(self, cr, uid, account, context=None): - """ Extension point to obtain analytic policy for an account """ - return account.user_type.partner_policy - - def _check_partner_required_msg(self, cr, uid, ids, context=None): - for move_line in self.browse(cr, uid, ids, context): - if move_line.debit == 0 and move_line.credit == 0: - continue - policy = self._get_partner_policy(cr, uid, - move_line.account_id, - context=context) - if policy == 'always' and not move_line.partner_id: - return _("Partner policy is set to 'Always' " - "with account %s '%s' but the " - "partner is missing in the account " - "move line with label '%s'." % - (move_line.account_id.code, - move_line.account_id.name, - move_line.name)) - elif policy == 'never' and move_line.partner_id: - return _("Partner policy is set to 'Never' " - "with account %s '%s' but the " - "account move line with label '%s' " - "has a partner '%s'." % - (move_line.account_id.code, - move_line.account_id.name, - move_line.name, - move_line.partner_id.name)) - - def _check_partner_required(self, cr, uid, ids, context=None): - return not self._check_partner_required_msg(cr, uid, ids, - context=context) - - _constraints = [ - (_check_partner_required, - _check_partner_required_msg, - ['partner_id', 'account_id', 'debit', 'credit']), - ] diff --git a/account_partner_required/models/__init__.py b/account_partner_required/models/__init__.py new file mode 100644 index 00000000..300089bd --- /dev/null +++ b/account_partner_required/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import account diff --git a/account_partner_required/models/account.py b/account_partner_required/models/account.py new file mode 100644 index 00000000..2a6bfd22 --- /dev/null +++ b/account_partner_required/models/account.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# © 2014-2016 Acsone (http://acsone.eu) +# © 2016 Akretion (http://www.akretion.com/) +# @author Stéphane Bidoul +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import models, fields, api, _ +from odoo.tools import float_is_zero +from odoo.exceptions import ValidationError + + +class AccountAccountType(models.Model): + _inherit = "account.account.type" + + @api.model + def _get_partner_policies(self): + """This is the method to be inherited for adding policies""" + return [('optional', _('Optional')), + ('always', _('Always')), + ('never', _('Never'))] + + partner_policy = fields.Selection( + _get_partner_policies, string='Policy for Partner Field', + required=True, default='optional', + help="Set the policy for the partner field : if you select " + "'Optional', the accountant is free to put a partner " + "on an account move line with this type of account ; " + "if you select 'Always', the accountant will get an error " + "message if there is no partner ; if you select 'Never', " + "the accountant will get an error message if a partner " + "is present.") + + +class AccountAccount(models.Model): + _inherit = 'account.account' + + @api.multi + def get_partner_policy(self): + """ Extension point to obtain partner policy for an account """ + self.ensure_one() + return self.user_type_id.partner_policy + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + @api.multi + def _check_partner_required_msg(self): + prec = self.env.user.company_id.currency_id.rounding + for line in self: + if ( + float_is_zero(line.debit, precision_rounding=prec) and + float_is_zero(line.credit, precision_rounding=prec)): + continue + policy = line.account_id.get_partner_policy() + if policy == 'always' and not line.partner_id: + return _("Partner policy is set to 'Always' " + "with account '%s' but the " + "partner is missing in the account " + "move line with label '%s'." % + (line.account_id.name_get()[0][1], + line.name)) + elif policy == 'never' and line.partner_id: + return _("Partner policy is set to 'Never' " + "with account '%s' but the " + "account move line with label '%s' " + "has a partner '%s'." % + (line.account_id.name_get()[0][1], + line.name, + line.partner_id.name)) + + @api.multi + @api.constrains('partner_id', 'account_id', 'debit', 'credit') + def _check_partner_required(self): + for line in self: + message = line._check_partner_required_msg() + if message: + raise ValidationError(message) diff --git a/account_partner_required/tests/test_account_partner_required.py b/account_partner_required/tests/test_account_partner_required.py index e66e7a68..c1921d16 100644 --- a/account_partner_required/tests/test_account_partner_required.py +++ b/account_partner_required/tests/test_account_partner_required.py @@ -1,131 +1,132 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Account partner required module for OpenERP -# Copyright (C) 2014 Acsone (http://acsone.eu). -# @author Stéphane Bidoul -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## +# -*- coding: utf-8 -*- +# © 2014-2016 Acsone (http://acsone.eu) +# © 2016 Akretion (http://www.akretion.com/) +# @author Stéphane Bidoul +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + from datetime import datetime - -from openerp.tests import common -from openerp.osv import orm +from odoo.tests import common +from odoo.exceptions import ValidationError -class test_account_partner_required(common.TransactionCase): +class TestAccountPartnerRequired(common.TransactionCase): def setUp(self): - super(test_account_partner_required, self).setUp() - self.account_obj = self.registry('account.account') - self.account_type_obj = self.registry('account.account.type') - self.move_obj = self.registry('account.move') - self.move_line_obj = self.registry('account.move.line') + super(TestAccountPartnerRequired, self).setUp() + self.account_obj = self.env['account.account'] + self.account_type_obj = self.env['account.account.type'] + self.move_obj = self.env['account.move'] + self.move_line_obj = self.env['account.move.line'] + self.sale_journal = self.env['account.journal'].create({ + 'type': 'sale', + 'code': 'SJXX', + 'name': 'Sale journal', + }) + liq_acc_type = self.env.ref('account.data_account_type_liquidity') + self.account1 = self.account_obj.create({ + 'code': '124242', + 'name': 'Test 1', + 'user_type_id': liq_acc_type.id, + }) + self.account_type_custom = self.account_type_obj.create({ + 'name': 'acc type test', + 'type': 'other', + 'partner_policy': 'optional', + }) + self.account2 = self.account_obj.create({ + 'code': '124243', + 'name': 'Test 2', + 'user_type_id': self.account_type_custom.id, + }) + self.account3 = self.account_obj.create({ + 'code': '124244', + 'name': 'Test 3', + 'user_type_id': self.account_type_custom.id, + }) def _create_move(self, with_partner, amount=100): date = datetime.now() - period_id = self.registry('account.period').find( - self.cr, self.uid, date, - context={'account_period_prefer_normal': True})[0] + if with_partner: + partner_id = self.env.ref('base.res_partner_1').id + else: + partner_id = False move_vals = { - 'journal_id': self.ref('account.sales_journal'), - 'period_id': period_id, + 'journal_id': self.sale_journal.id, 'date': date, - } - move_id = self.move_obj.create(self.cr, self.uid, move_vals) - self.move_line_obj.create(self.cr, self.uid, - {'move_id': move_id, - 'name': '/', - 'debit': 0, - 'credit': amount, - 'account_id': self.ref('account.a_sale')}) - move_line_id = self.move_line_obj.create( - self.cr, self.uid, - { - 'move_id': move_id, - 'name': '/', - 'debit': amount, - 'credit': 0, - 'account_id': self.ref('account.a_recv'), - 'partner_id': self.ref('base.res_partner_1') if - with_partner else False + 'line_ids': [ + (0, 0, { + 'name': '/', + 'debit': 0, + 'credit': amount, + 'account_id': self.account1.id, + }), + (0, 0, { + 'name': '/', + 'debit': amount, + 'credit': 0, + 'account_id': self.account2.id, + 'partner_id': partner_id, + }) + ], } - ) - return move_line_id - - def _set_partner_policy(self, policy, aref='account.a_recv'): - account_type = self.account_obj.browse(self.cr, self.uid, - self.ref(aref)).user_type - self.account_type_obj.write(self.cr, self.uid, account_type.id, - {'partner_policy': policy}) + move = self.move_obj.create(move_vals) + move_line = False + for line in move.line_ids: + if line.account_id == self.account2: + move_line = line + break + return move_line def test_optional(self): self._create_move(with_partner=False) self._create_move(with_partner=True) def test_always_no_partner(self): - self._set_partner_policy('always') - with self.assertRaises(orm.except_orm): + self.account_type_custom.partner_policy = 'always' + with self.assertRaises(ValidationError): self._create_move(with_partner=False) def test_always_no_partner_0(self): # accept missing partner when debit=credit=0 - self._set_partner_policy('always') + self.account_type_custom.partner_policy = 'always' self._create_move(with_partner=False, amount=0) def test_always_with_partner(self): - self._set_partner_policy('always') + self.account_type_custom.partner_policy = 'always' self._create_move(with_partner=True) def test_never_no_partner(self): - self._set_partner_policy('never') + self.account_type_custom.partner_policy = 'never' self._create_move(with_partner=False) def test_never_with_partner(self): - self._set_partner_policy('never') - with self.assertRaises(orm.except_orm): + self.account_type_custom.partner_policy = 'never' + with self.assertRaises(ValidationError): self._create_move(with_partner=True) def test_never_with_partner_0(self): + self.account_type_custom.partner_policy = 'never' # accept partner when debit=credit=0 - self._set_partner_policy('never') self._create_move(with_partner=True, amount=0) def test_always_remove_partner(self): # remove partner when policy is always - self._set_partner_policy('always') - line_id = self._create_move(with_partner=True) - with self.assertRaises(orm.except_orm): - self.move_line_obj.write(self.cr, self.uid, [line_id], - {'partner_id': False}) + self.account_type_custom.partner_policy = 'always' + line = self._create_move(with_partner=True) + with self.assertRaises(ValidationError): + line.write({'partner_id': False}) def test_change_account(self): - self._set_partner_policy('always', aref='account.a_pay') - line_id = self._create_move(with_partner=False) - # change account to a_pay with policy always but missing partner - with self.assertRaises(orm.except_orm): - self.move_line_obj.write(self.cr, self.uid, [line_id], - {'account_id': self.ref('account.a_pay')}) - # change account to a_pay with policy always with partner -> ok - self.move_line_obj.write( - self.cr, - self.uid, - [line_id], - { - 'account_id': self.ref('account.a_pay'), - 'partner_id': self.ref('base.res_partner_1') - } - ) + self.account_type_custom.partner_policy = 'optional' + line = self._create_move(with_partner=False) + # change account to an account with policy always but missing partner + self.account_type_custom.partner_policy = 'always' + with self.assertRaises(ValidationError): + line.write({'account_id': self.account3.id}) + # change account to an account with policy always with partner + line.write({ + 'account_id': self.account3.id, + 'partner_id': self.env.ref('base.res_partner_1').id + }) diff --git a/account_partner_required/account_view.xml b/account_partner_required/views/account.xml similarity index 65% rename from account_partner_required/account_view.xml rename to account_partner_required/views/account.xml index 85d1c453..3858fe87 100644 --- a/account_partner_required/account_view.xml +++ b/account_partner_required/views/account.xml @@ -1,21 +1,19 @@ - - + - + account_partner_required.account_type_form account.account.type - - + + @@ -25,11 +23,10 @@ account.account.type - + - - +