From edc6205fcb1e6bf7e492a8e5d5f7eaed2d00fcb5 Mon Sep 17 00:00:00 2001 From: eLBati Date: Fri, 17 Feb 2012 15:03:46 +0100 Subject: [PATCH 01/89] [ADD] first prototype l10n_it_withholding_tax. Handling withholding maturity date [ADD] author [FIX] copyright & description [IMP] l10n_it_withholding_tax - description --- l10n_it_withholding_tax/AUTHORS.txt | 2 + l10n_it_withholding_tax/__init__.py | 26 ++++++++ l10n_it_withholding_tax/__openerp__.py | 47 +++++++++++++++ l10n_it_withholding_tax/account.py | 75 ++++++++++++++++++++++++ l10n_it_withholding_tax/account_view.xml | 18 ++++++ 5 files changed, 168 insertions(+) create mode 100644 l10n_it_withholding_tax/AUTHORS.txt create mode 100644 l10n_it_withholding_tax/__init__.py create mode 100644 l10n_it_withholding_tax/__openerp__.py create mode 100644 l10n_it_withholding_tax/account.py create mode 100644 l10n_it_withholding_tax/account_view.xml diff --git a/l10n_it_withholding_tax/AUTHORS.txt b/l10n_it_withholding_tax/AUTHORS.txt new file mode 100644 index 000000000000..b60a9687c637 --- /dev/null +++ b/l10n_it_withholding_tax/AUTHORS.txt @@ -0,0 +1,2 @@ +Lorenzo Battistini +Paolo Chiara diff --git a/l10n_it_withholding_tax/__init__.py b/l10n_it_withholding_tax/__init__.py new file mode 100644 index 000000000000..8ef76fabc8cb --- /dev/null +++ b/l10n_it_withholding_tax/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2012 Associazione OpenERP Italia +# (). +# All Rights Reserved +# Copyright (C) 2012 Agile Business Group sagl () +# Copyright (C) 2012 Domsense srl () +# All Rights Reserved +# +# 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 . +# +############################################################################## + +import account diff --git a/l10n_it_withholding_tax/__openerp__.py b/l10n_it_withholding_tax/__openerp__.py new file mode 100644 index 000000000000..8be322cf5f69 --- /dev/null +++ b/l10n_it_withholding_tax/__openerp__.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2012 Associazione OpenERP Italia +# (). +# All Rights Reserved +# Copyright (C) 2012 Agile Business Group sagl () +# Copyright (C) 2012 Domsense srl () +# All Rights Reserved +# +# 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 . +# +############################################################################## +{ + 'name': "Italian Localisation - Ritenute d'acconto", + 'version': '0.1', + 'category': 'Localisation/Italy', + 'description': """ + Modulo per le ritenute d'acconto sulle fatture fornitore + +http://planet.domsense.com/2012/06/come-registrare-in-openerp-le-fatture-fornitore-con-ritenuta-dacconto/ + + http://wiki.openerp-italia.org/doku.php/area_utente/requisiti/ritenuta_d_acconto +""", + 'author': 'OpenERP Italian Community', + 'website': 'http://www.openerp-italia.org', + 'license': 'AGPL-3', + "depends" : ['account_invoice_template'], + "init_xml" : [ + 'account_view.xml', + ], + "update_xml" : [], + "demo_xml" : [], + "active": False, + "installable": True +} diff --git a/l10n_it_withholding_tax/account.py b/l10n_it_withholding_tax/account.py new file mode 100644 index 000000000000..c9cf18109013 --- /dev/null +++ b/l10n_it_withholding_tax/account.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2012 Associazione OpenERP Italia +# (). +# All Rights Reserved +# Copyright (C) 2012 Agile Business Group sagl () +# Copyright (C) 2012 Domsense srl () +# All Rights Reserved +# +# 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 osv import fields, osv +from tools.translate import _ + +class account_tax(osv.osv): + _inherit = 'account.tax' + _columns = { + 'withholding_tax': fields.boolean('Withholding Tax'), + 'withholding_payment_term_id': fields.many2one('account.payment.term', 'Withholding Payment Term'), + } +account_tax() + +class account_invoice(osv.osv): + _inherit = "account.invoice" + + def action_move_create(self, cr, uid, ids, context=None): + res = super(account_invoice, self).action_move_create(cr, uid, ids, context=context) + tax_pool = self.pool.get('account.tax') + term_pool = self.pool.get('account.payment.term') + for inv in self.browse(cr, uid, ids, context=context): + for move_line in inv.move_id.line_id: + if move_line.tax_code_id: + tax_ids = tax_pool.search(cr, uid, [('tax_code_id', '=', move_line.tax_code_id.id)]) + is_withholding = False + for tax in tax_pool.browse(cr, uid, tax_ids): + if tax.withholding_tax: + is_withholding = True + if is_withholding: + if len(tax_ids) > 1: + raise osv.except_osv(_('Error'), + _('Too many taxes associated to tax.code %s') % move_line.tax_code_id.name) + if not tax_ids: + raise osv.except_osv(_('Error'), + _('No taxes associated to tax.code %s') % move_line.tax_code_id.name) + tax = tax_pool.browse(cr, uid, tax_ids[0]) + if tax.withholding_tax and tax.withholding_payment_term_id: + due_list = term_pool.compute( + cr, uid, tax.withholding_payment_term_id.id, move_line.tax_amount, + date_ref=inv.date_invoice, context=context) + if len(due_list) > 1: + raise osv.except_osv(_('Error'), + _('The payment term %s has too many due dates') + % tax.withholding_payment_term_id.name) + if len(due_list) == 0: + raise osv.except_osv(_('Error'), + _('The payment term %s does not have due dates') + % tax.withholding_payment_term_id.name) + move_line.write({'date_maturity': due_list[0][0]}) + return res + +account_invoice() diff --git a/l10n_it_withholding_tax/account_view.xml b/l10n_it_withholding_tax/account_view.xml new file mode 100644 index 000000000000..617775bcf61a --- /dev/null +++ b/l10n_it_withholding_tax/account_view.xml @@ -0,0 +1,18 @@ + + + + + + account.tax.form + account.tax + form + + + + + + + + + + From 008117d544c55db2b1e0589fdea4ce40b8bdfc8b Mon Sep 17 00:00:00 2001 From: Lorenzo Battistini Date: Tue, 17 Jul 2012 16:51:47 +0200 Subject: [PATCH 02/89] [REM] l10n_it_withholding_tax --- l10n_it_withholding_tax/AUTHORS.txt | 2 - l10n_it_withholding_tax/__init__.py | 26 -------- l10n_it_withholding_tax/__openerp__.py | 47 --------------- l10n_it_withholding_tax/account.py | 75 ------------------------ l10n_it_withholding_tax/account_view.xml | 18 ------ 5 files changed, 168 deletions(-) delete mode 100644 l10n_it_withholding_tax/AUTHORS.txt delete mode 100644 l10n_it_withholding_tax/__init__.py delete mode 100644 l10n_it_withholding_tax/__openerp__.py delete mode 100644 l10n_it_withholding_tax/account.py delete mode 100644 l10n_it_withholding_tax/account_view.xml diff --git a/l10n_it_withholding_tax/AUTHORS.txt b/l10n_it_withholding_tax/AUTHORS.txt deleted file mode 100644 index b60a9687c637..000000000000 --- a/l10n_it_withholding_tax/AUTHORS.txt +++ /dev/null @@ -1,2 +0,0 @@ -Lorenzo Battistini -Paolo Chiara diff --git a/l10n_it_withholding_tax/__init__.py b/l10n_it_withholding_tax/__init__.py deleted file mode 100644 index 8ef76fabc8cb..000000000000 --- a/l10n_it_withholding_tax/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2012 Associazione OpenERP Italia -# (). -# All Rights Reserved -# Copyright (C) 2012 Agile Business Group sagl () -# Copyright (C) 2012 Domsense srl () -# All Rights Reserved -# -# 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 . -# -############################################################################## - -import account diff --git a/l10n_it_withholding_tax/__openerp__.py b/l10n_it_withholding_tax/__openerp__.py deleted file mode 100644 index 8be322cf5f69..000000000000 --- a/l10n_it_withholding_tax/__openerp__.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2012 Associazione OpenERP Italia -# (). -# All Rights Reserved -# Copyright (C) 2012 Agile Business Group sagl () -# Copyright (C) 2012 Domsense srl () -# All Rights Reserved -# -# 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 . -# -############################################################################## -{ - 'name': "Italian Localisation - Ritenute d'acconto", - 'version': '0.1', - 'category': 'Localisation/Italy', - 'description': """ - Modulo per le ritenute d'acconto sulle fatture fornitore - -http://planet.domsense.com/2012/06/come-registrare-in-openerp-le-fatture-fornitore-con-ritenuta-dacconto/ - - http://wiki.openerp-italia.org/doku.php/area_utente/requisiti/ritenuta_d_acconto -""", - 'author': 'OpenERP Italian Community', - 'website': 'http://www.openerp-italia.org', - 'license': 'AGPL-3', - "depends" : ['account_invoice_template'], - "init_xml" : [ - 'account_view.xml', - ], - "update_xml" : [], - "demo_xml" : [], - "active": False, - "installable": True -} diff --git a/l10n_it_withholding_tax/account.py b/l10n_it_withholding_tax/account.py deleted file mode 100644 index c9cf18109013..000000000000 --- a/l10n_it_withholding_tax/account.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2012 Associazione OpenERP Italia -# (). -# All Rights Reserved -# Copyright (C) 2012 Agile Business Group sagl () -# Copyright (C) 2012 Domsense srl () -# All Rights Reserved -# -# 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 osv import fields, osv -from tools.translate import _ - -class account_tax(osv.osv): - _inherit = 'account.tax' - _columns = { - 'withholding_tax': fields.boolean('Withholding Tax'), - 'withholding_payment_term_id': fields.many2one('account.payment.term', 'Withholding Payment Term'), - } -account_tax() - -class account_invoice(osv.osv): - _inherit = "account.invoice" - - def action_move_create(self, cr, uid, ids, context=None): - res = super(account_invoice, self).action_move_create(cr, uid, ids, context=context) - tax_pool = self.pool.get('account.tax') - term_pool = self.pool.get('account.payment.term') - for inv in self.browse(cr, uid, ids, context=context): - for move_line in inv.move_id.line_id: - if move_line.tax_code_id: - tax_ids = tax_pool.search(cr, uid, [('tax_code_id', '=', move_line.tax_code_id.id)]) - is_withholding = False - for tax in tax_pool.browse(cr, uid, tax_ids): - if tax.withholding_tax: - is_withholding = True - if is_withholding: - if len(tax_ids) > 1: - raise osv.except_osv(_('Error'), - _('Too many taxes associated to tax.code %s') % move_line.tax_code_id.name) - if not tax_ids: - raise osv.except_osv(_('Error'), - _('No taxes associated to tax.code %s') % move_line.tax_code_id.name) - tax = tax_pool.browse(cr, uid, tax_ids[0]) - if tax.withholding_tax and tax.withholding_payment_term_id: - due_list = term_pool.compute( - cr, uid, tax.withholding_payment_term_id.id, move_line.tax_amount, - date_ref=inv.date_invoice, context=context) - if len(due_list) > 1: - raise osv.except_osv(_('Error'), - _('The payment term %s has too many due dates') - % tax.withholding_payment_term_id.name) - if len(due_list) == 0: - raise osv.except_osv(_('Error'), - _('The payment term %s does not have due dates') - % tax.withholding_payment_term_id.name) - move_line.write({'date_maturity': due_list[0][0]}) - return res - -account_invoice() diff --git a/l10n_it_withholding_tax/account_view.xml b/l10n_it_withholding_tax/account_view.xml deleted file mode 100644 index 617775bcf61a..000000000000 --- a/l10n_it_withholding_tax/account_view.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - account.tax.form - account.tax - form - - - - - - - - - - From 3350cb1fc75b4b079575cdd8ffb4152bf270cfae Mon Sep 17 00:00:00 2001 From: Lorenzo Battistini Date: Wed, 17 Apr 2013 12:16:04 +0200 Subject: [PATCH 03/89] [add] l10n_it_withholding_tax from 6.1 [fix] descriptions [fix] dependency [fix] config [fix] config view [fix] using invoice partner in reconcile [imp] using tax authority partner [add] tests first version [imp] tests [imp] tests [ADD] field help [fix] using right date and period when paying --- l10n_it_withholding_tax/AUTHORS.txt | 2 + l10n_it_withholding_tax/__init__.py | 24 +++ l10n_it_withholding_tax/__openerp__.py | 60 ++++++ l10n_it_withholding_tax/account.py | 204 ++++++++++++++++++ l10n_it_withholding_tax/account_demo.xml | 19 ++ l10n_it_withholding_tax/account_view.xml | 71 ++++++ l10n_it_withholding_tax/i18n/it.mo | Bin 0 -> 2515 bytes l10n_it_withholding_tax/i18n/it.po | 150 +++++++++++++ .../test/purchase_payment.yml | 105 +++++++++ 9 files changed, 635 insertions(+) create mode 100644 l10n_it_withholding_tax/AUTHORS.txt create mode 100644 l10n_it_withholding_tax/__init__.py create mode 100644 l10n_it_withholding_tax/__openerp__.py create mode 100644 l10n_it_withholding_tax/account.py create mode 100644 l10n_it_withholding_tax/account_demo.xml create mode 100644 l10n_it_withholding_tax/account_view.xml create mode 100644 l10n_it_withholding_tax/i18n/it.mo create mode 100644 l10n_it_withholding_tax/i18n/it.po create mode 100644 l10n_it_withholding_tax/test/purchase_payment.yml diff --git a/l10n_it_withholding_tax/AUTHORS.txt b/l10n_it_withholding_tax/AUTHORS.txt new file mode 100644 index 000000000000..b60a9687c637 --- /dev/null +++ b/l10n_it_withholding_tax/AUTHORS.txt @@ -0,0 +1,2 @@ +Lorenzo Battistini +Paolo Chiara diff --git a/l10n_it_withholding_tax/__init__.py b/l10n_it_withholding_tax/__init__.py new file mode 100644 index 000000000000..ae9ed0914416 --- /dev/null +++ b/l10n_it_withholding_tax/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2012 Agile Business Group sagl () +# Copyright (C) 2012 Domsense srl () +# Copyright (C) 2012-2013 Associazione OpenERP Italia +# (). +# +# 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 . +# +############################################################################## + +import account diff --git a/l10n_it_withholding_tax/__openerp__.py b/l10n_it_withholding_tax/__openerp__.py new file mode 100644 index 000000000000..ba998458109b --- /dev/null +++ b/l10n_it_withholding_tax/__openerp__.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2012 Agile Business Group sagl () +# Copyright (C) 2012 Domsense srl () +# Copyright (C) 2012-2013 Associazione OpenERP Italia +# (). +# +# 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 . +# +############################################################################## +{ + 'name': "Italian Localisation - Withholding tax", + 'version': '0.2', + 'category': 'Localisation/Italy', + 'description': """ +Ritenute d'acconto sulle fatture fornitore +========================================== + +Per utilizzare il modulo bisogna configurare i campi associati alla company: + - Termine di pagamento della ritenuta + - Conto di debito per le ritenute da versare + - Sezionale che conterrà le registrazioni legate alla ritenuta + +Durante la compilazione di una fattura fornitore con ritenuta d'acconto, l'utente dovrà specificare l'importo della ritenuta. + +Requisiti +--------- +http://wiki.openerp-italia.org/doku.php/area_utente/requisiti/ritenuta_d_acconto + +Howto +----- +http://planet.domsense.com/2012/06/come-registrare-in-openerp-le-fatture-fornitore-con-ritenuta-dacconto/ +""", + 'author': 'OpenERP Italian Community', + 'website': 'http://www.openerp-italia.org', + 'license': 'AGPL-3', + "depends" : ['account_voucher_cash_basis'], + "data" : [ + 'account_view.xml',], + "demo" : [ + 'account_demo.xml', + ], + 'test' : [ + 'test/purchase_payment.yml', + ], + "active": False, + "installable": True +} diff --git a/l10n_it_withholding_tax/account.py b/l10n_it_withholding_tax/account.py new file mode 100644 index 000000000000..9338813558a1 --- /dev/null +++ b/l10n_it_withholding_tax/account.py @@ -0,0 +1,204 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2012 Agile Business Group sagl () +# Copyright (C) 2012 Domsense srl () +# Copyright (C) 2012-2013 Associazione OpenERP Italia +# (). +# +# 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 fields, orm +from openerp.tools.translate import _ +import decimal_precision as dp + +class res_company(orm.Model): + _inherit = 'res.company' + _columns = { + 'withholding_payment_term_id': fields.many2one('account.payment.term', + 'Withholding tax Payment Term', + help="The withholding tax will have to be paid within this term"), + 'withholding_account_id': fields.many2one('account.account','Withholding account', + help='Payable account used for amount due to tax authority', + domain=[('type', '=', 'payable')]), + 'withholding_journal_id': fields.many2one('account.journal','Withholding journal', + help="Journal used for registration of witholding amounts to be paid"), + 'authority_partner_id': fields.many2one('res.partner', 'Tax Authority Partner'), + } + +class account_config_settings(orm.TransientModel): + _inherit = 'account.config.settings' + _columns = { + 'withholding_payment_term_id': fields.related( + 'company_id', 'withholding_payment_term_id', + type='many2one', + relation="account.payment.term", + string="Withholding tax Payment Term"), + 'withholding_account_id': fields.related( + 'company_id', 'withholding_account_id', + type='many2one', + relation="account.account", + string="Withholding account", + help='Payable account used for amount due to tax authority', + domain=[('type', '=', 'payable')]), + 'withholding_journal_id': fields.related( + 'company_id', 'withholding_journal_id', + type='many2one', + relation="account.journal", + string="Withholding journal", + help='Journal used for registration of witholding amounts to be paid'), + 'authority_partner_id': fields.related( + 'company_id', 'authority_partner_id', + type='many2one', + relation="res.partner", + string="Tax Authority Partner"), + } + + def onchange_company_id(self, cr, uid, ids, company_id, context=None): + res = super(account_config_settings, self).onchange_company_id(cr, uid, ids, company_id, context=context) + if company_id: + company = self.pool.get('res.company').browse(cr, uid, company_id, context=context) + res['value'].update({ + 'withholding_payment_term_id': (company.withholding_payment_term_id + and company.withholding_payment_term_id.id or False), + 'withholding_account_id': (company.withholding_account_id + and company.withholding_account_id.id or False), + 'withholding_journal_id': (company.withholding_journal_id + and company.withholding_journal_id.id or False), + 'authority_partner_id': (company.authority_partner_id + and company.authority_partner_id.id or False), + }) + else: + res['value'].update({ + 'withholding_payment_term_id': False, + 'withholding_account_id': False, + 'withholding_journal_id': False, + 'authority_partner_id': False, + }) + return res + +class account_invoice(orm.Model): + + def _net_pay(self, cr, uid, ids, field_name, arg, context=None): + res = {} + for invoice in self.browse(cr, uid, ids, context): + res[invoice.id] = invoice.amount_total - invoice.withholding_amount + return res + + _inherit = "account.invoice" + + _columns = { + 'withholding_amount': fields.float('Withholding amount', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}), + 'has_withholding': fields.boolean('With withholding tax', readonly=True, states={'draft':[('readonly',False)]}), + 'net_pay': fields.function(_net_pay, string="Net Pay"), + } + +class account_voucher(orm.Model): + _inherit = "account.voucher" + + _columns = { + 'withholding_move_ids': fields.many2many('account.move', 'voucher_withholding_move_rel', 'voucher_id', 'move_id', 'Withholding Tax Entries', readonly=True), + } + + def reconcile_withholding_move(self, cr, uid, invoice, wh_move, context=None): + line_pool=self.pool.get('account.move.line') + rec_ids = [] + for inv_move_line in invoice.move_id.line_id: + if inv_move_line.account_id.type == 'payable' and not inv_move_line.reconcile_id: + rec_ids.append(inv_move_line.id) + for wh_line in wh_move.line_id: + if wh_line.account_id.type == 'payable' and invoice.company_id.withholding_account_id and invoice.company_id.withholding_account_id.id != wh_line.account_id.id and not wh_line.reconcile_id: + rec_ids.append(wh_line.id) + return line_pool.reconcile_partial(cr, uid, rec_ids, type='auto', context=context) + + def action_move_line_create(self, cr, uid, ids, context=None): + res = super(account_voucher,self).action_move_line_create(cr, uid, ids, context) + inv_pool = self.pool.get('account.invoice') + move_pool = self.pool.get('account.move') + tax_pool = self.pool.get('account.tax') + curr_pool = self.pool.get('res.currency') + term_pool = self.pool.get('account.payment.term') + priod_obj = self.pool.get('account.period') + for voucher in self.browse(cr, uid, ids, context): + amounts_by_invoice = super(account_voucher,self).allocated_amounts_grouped_by_invoice(cr, uid,voucher, context) + for inv_id in amounts_by_invoice: + invoice = inv_pool.browse(cr, uid, inv_id, context) + if invoice.withholding_amount: + # only for supplier payments + if voucher.type != 'payment': + raise orm.except_orm(_('Error'), _('Can\'t handle withholding tax with voucher of type other than payment')) + if not invoice.company_id.withholding_account_id: + raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding account') ) + if not invoice.company_id.withholding_payment_term_id: + raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding Payment Term') ) + if not invoice.company_id.withholding_journal_id: + raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding journal') ) + if not invoice.company_id.authority_partner_id: + raise orm.except_orm(_('Error'), _('The company does not have an associated Tax Authority partner') ) + # compute the new amount proportionally to paid amount + new_line_amount = curr_pool.round(cr, uid, voucher.company_id.currency_id, ((amounts_by_invoice[invoice.id]['allocated'] + amounts_by_invoice[invoice.id]['write-off']) / invoice.net_pay) * invoice.withholding_amount) + + # compute the due date + due_list = term_pool.compute( + cr, uid, invoice.company_id.withholding_payment_term_id.id, new_line_amount, + date_ref=voucher.date or invoice.date_invoice, context=context) + if len(due_list) > 1: + raise orm.except_orm(_('Error'), + _('The payment term %s has too many due dates') + % invoice.company_id.withholding_payment_term_id.name) + if len(due_list) == 0: + raise orm.except_orm(_('Error'), + _('The payment term %s does not have due dates') + % invoice.company_id.withholding_payment_term_id.name) + + period_ids = priod_obj.find(cr, uid, dt=voucher.date, context=context) + new_move = { + 'journal_id': invoice.company_id.withholding_journal_id.id, + 'period_id': period_ids and period_ids[0] or False, + 'date': voucher.date, + 'line_id': [ + (0,0,{ + 'name': invoice.number, + 'account_id': invoice.account_id.id, + 'partner_id': invoice.partner_id.id, + 'debit': new_line_amount, + 'credit': 0.0, + }), + (0,0,{ + 'name': _('Payable withholding - ') + invoice.number, + 'account_id': invoice.company_id.withholding_account_id.id, + 'partner_id': invoice.company_id.authority_partner_id.id, + 'debit': 0.0, + 'credit': new_line_amount, + 'date_maturity': due_list[0][0], + }), + ] + } + move_id = self.pool.get('account.move').create(cr, uid, new_move, context=context) + self.reconcile_withholding_move(cr, uid, invoice, move_pool.browse(cr, uid, move_id, context), context) + voucher.write({'withholding_move_ids': [(4, move_id)]}) + return res + + def cancel_voucher(self, cr, uid, ids, context=None): + res = super(account_voucher,self).cancel_voucher(cr, uid, ids, context) + reconcile_pool = self.pool.get('account.move.reconcile') + move_pool = self.pool.get('account.move') + for voucher in self.browse(cr, uid, ids, context=context): + recs = [] + for move in voucher.withholding_move_ids: + move_pool.button_cancel(cr, uid, [move.id]) + move_pool.unlink(cr, uid, [move.id]) + return res diff --git a/l10n_it_withholding_tax/account_demo.xml b/l10n_it_withholding_tax/account_demo.xml new file mode 100644 index 000000000000..26c55edfb9fa --- /dev/null +++ b/l10n_it_withholding_tax/account_demo.xml @@ -0,0 +1,19 @@ + + + + + + X1115 + Withholding tax to pay + + payable + + + + + Tax authority + + + + + diff --git a/l10n_it_withholding_tax/account_view.xml b/l10n_it_withholding_tax/account_view.xml new file mode 100644 index 000000000000..f09c3b7c92a3 --- /dev/null +++ b/l10n_it_withholding_tax/account_view.xml @@ -0,0 +1,71 @@ + + + + + + + + view_account_config_settings + account.config.settings + + + + + + + + + + + + + + account.invoice.supplier.form + account.invoice + + + + + + + + + + + + + + + + account.voucher.payment.form.wh.move + account.voucher + + + + + + + + + + + diff --git a/l10n_it_withholding_tax/i18n/it.mo b/l10n_it_withholding_tax/i18n/it.mo new file mode 100644 index 0000000000000000000000000000000000000000..2ad76334181ea3809cafde28050b62791084b745 GIT binary patch literal 2515 zcmcJPOK%)S5XT1yB-!vt!Xvzd$|#W~tXXzV0@em18^@MxVrR9PB;tb9JJY+{(Mzea0wiP?C)#v8Sp3Y4EPuLH24q5@ts02 z+&>F)9xEW*T?f~ZO9q}o|NFe$a#DMJ_Y^=avr~c z9MAD%L9hwF0=@xC@GbBz_$v4_$a(w?avlWnINtX_j`subNzj7q|KsZaXW)zIe+9DL z4=zWt@3^Q#!#a0S0$;vplPK_kRlR5QZ zOOK3-<%G1GXI(6j<<3)AQm)m9xuhY6%7w-Y!M4e*7AfUUCe$+)j{C}aE4(tAL*-Pe zOhm>>JMxCT4TVaAUFoSU#sMDDMdG3qX6CM(LkZT!G}c1oaA=jEO`2CLq#znhk{VND zq$|=M2&4)LgmWfVP#~e3b0TAX7LX!ovqL$k0zcH;Tcw73=4z42{lYI47S&#pN2qkp z?Msn`N|2sA&~_kLeM6bh&}M4NO6)&#!Mr>Xbl=e4^2wSXpJcsftk~r}W|IWx&3G&K zsJ{Ovwxd|DZOtti`*14>Z%7V7WzGK{3i5Zlhy&c-aK zX1!5cH`*ibFv9(AVTW(~*N3T4`Xa>xVV(5vT#q)xm6;vK(UUgZKnPqdTC~ztzSd52 zE7EY&*vw&}pei!B>)MO1O67woH*0s4)QK$1%mfRxi<^J%8yXtt6faiP9E39OaaqAXP=EKUWq@T?7h`Mn#|2977sOs`RKY%Ox<)8mR-x6z<^66j zk@wHc`TH+(uE{$%(}Ig@Rr~H=YYU1S6r9NpKyOJi!C7vus{cdj!HGvz$JXLhlv?7j n#tPSo$EITN#W1sOWIQJ{{XNTZI>eP+X;th@De&~yK@0o~W_;8h literal 0 HcmV?d00001 diff --git a/l10n_it_withholding_tax/i18n/it.po b/l10n_it_withholding_tax/i18n/it.po new file mode 100644 index 000000000000..79515f45df14 --- /dev/null +++ b/l10n_it_withholding_tax/i18n/it.po @@ -0,0 +1,150 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * l10n_it_withholding_tax +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 6.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-10-12 15:54+0000\n" +"PO-Revision-Date: 2012-10-12 18:02+0100\n" +"Last-Translator: Franco Tampieri \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:90 +#, python-format +msgid "The company does not have an associated Withholding Payment Term" +msgstr "L'Azienda non ha associato nessun Termine di pagamento per le Ritenute" + +#. module: l10n_it_withholding_tax +#: constraint:res.company:0 +msgid "Error! You can not create recursive companies." +msgstr "Errore! Non è possibile creare aziende ricorsive." + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:106 +#, python-format +msgid "The payment term %s does not have due dates" +msgstr "The payment term %s does not have due dates" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:102 +#, python-format +msgid "The payment term %s has too many due dates" +msgstr "The payment term %s has too many due dates" + +#. module: l10n_it_withholding_tax +#: view:account.voucher:0 +msgid "Withholding tax entries" +msgstr "Voci Tasse Ritenute" + +#. module: l10n_it_withholding_tax +#: field:account.invoice,has_withholding:0 +msgid "With withholding tax" +msgstr "Con tasse ritenute" + +#. module: l10n_it_withholding_tax +#: field:res.company,withholding_payment_term_id:0 +msgid "Withholding tax Payment Term" +msgstr "Termini Pagamento Ritenute" + +#. module: l10n_it_withholding_tax +#: field:res.company,withholding_account_id:0 +msgid "Withholding account" +msgstr "Conto Ritenute" + +#. module: l10n_it_withholding_tax +#: sql_constraint:res.company:0 +msgid "The company name must be unique !" +msgstr "Il nome azienda deve essere unico!" + +#. module: l10n_it_withholding_tax +#: field:account.invoice,net_pay:0 +msgid "Net Pay" +msgstr "Netto da Pagare" + +#. module: l10n_it_withholding_tax +#: model:ir.model,name:l10n_it_withholding_tax.model_res_company +msgid "Companies" +msgstr "Aziende" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:92 +#, python-format +msgid "The company does not have an associated Withholding journal" +msgstr "L'Azienda non ha un Sezionale associato per le Ritenute" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:86 +#: code:addons/l10n_it_withholding_tax/account.py:88 +#: code:addons/l10n_it_withholding_tax/account.py:90 +#: code:addons/l10n_it_withholding_tax/account.py:92 +#: code:addons/l10n_it_withholding_tax/account.py:101 +#: code:addons/l10n_it_withholding_tax/account.py:105 +#, python-format +msgid "Error" +msgstr "Errore" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:86 +#, python-format +msgid "Can't handle withholding tax with voucher of type other than payment" +msgstr "Can't handle withholding tax with voucher of type other than payment" + +#. module: l10n_it_withholding_tax +#: help:res.company,withholding_account_id:0 +msgid "Payable account used for amount due to tax authority" +msgstr "Payable account used for amount due to tax authority" + +#. module: l10n_it_withholding_tax +#: sql_constraint:account.invoice:0 +msgid "Invoice Number must be unique per Company!" +msgstr "Nell'azienda il numero fattura dev'essere univoco!" + +#. module: l10n_it_withholding_tax +#: help:res.company,withholding_journal_id:0 +msgid "Journal used for registration of witholding amounts to be paid" +msgstr "Journal used for registration of witholding amounts to be paid" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:119 +#, python-format +msgid "Payable withholding - " +msgstr "Ritenute Pagabili - " + +#. module: l10n_it_withholding_tax +#: model:ir.model,name:l10n_it_withholding_tax.model_account_voucher +msgid "Accounting Voucher" +msgstr "Voucher contabile" + +#. module: l10n_it_withholding_tax +#: field:account.invoice,withholding_amount:0 +msgid "Withholding amount" +msgstr "Totale Ritenute" + +#. module: l10n_it_withholding_tax +#: model:ir.model,name:l10n_it_withholding_tax.model_account_invoice +msgid "Invoice" +msgstr "Fattura" + +#. module: l10n_it_withholding_tax +#: field:res.company,withholding_journal_id:0 +msgid "Withholding journal" +msgstr "Sezionale Ritenute" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:88 +#, python-format +msgid "The company does not have an associated Withholding account" +msgstr "L'Azienda non ha un conto associato per le Ritenute" + +#. module: l10n_it_withholding_tax +#: field:account.voucher,withholding_move_ids:0 +msgid "Withholding Tax Entries" +msgstr "Voci Tasse Ritenute" + diff --git a/l10n_it_withholding_tax/test/purchase_payment.yml b/l10n_it_withholding_tax/test/purchase_payment.yml new file mode 100644 index 000000000000..910a69acad19 --- /dev/null +++ b/l10n_it_withholding_tax/test/purchase_payment.yml @@ -0,0 +1,105 @@ +- + I configure the main company +- + !record {model: res.company, id: base.main_company}: + withholding_payment_term_id: account.account_payment_term + withholding_account_id: a_witholding + withholding_journal_id: account.miscellaneous_journal + authority_partner_id: tax_authority +- + In order to test account invoice I create a new supplier invoice +- + I create a Tax Codes +- + !record {model: account.tax.code, id: tax_case}: + name: Tax_case + company_id: base.main_company + sign: 1 +- + I create a Tax +- + !record {model: account.tax, id: tax10}: + name: Tax 10.0 + amount: 10.0 + type: fixed + sequence: 1 + company_id: base.main_company + type_tax_use: all + tax_code_id: tax_case +- + I set the context +- + !context + 'type': 'in_invoice' +- + I create a supplier invoice +- + !record {model: account.invoice, id: account_invoice_supplier_0, view: invoice_supplier_form}: + account_id: account.a_pay + company_id: base.main_company + currency_id: base.EUR + invoice_line: + - account_id: account.a_expense + name: 'Lawyer service' + price_unit: 100.0 + quantity: 1.0 + invoice_line_tax_id: + - tax10 + journal_id: account.expenses_journal + partner_id: base.res_partner_12 + has_withholding: True + withholding_amount: 20.0 +- + I check that Initially supplier invoice state is "Draft" +- + !assert {model: account.invoice, id: account_invoice_supplier_0}: + - state == 'draft' +- + I change the state of invoice to open by clicking Validate button +- + !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_supplier_0} +- + I check that the invoice state is now "Open" and 'Net Pay' is 90 +- + !assert {model: account.invoice, id: account_invoice_supplier_0}: + - state == 'open' + - net_pay == 90.0 +- + I create the voucher of payment with 90 +- + !record {model: account.voucher, id: account_voucher_0, view: account_voucher.view_vendor_payment_form}: + account_id: account.cash + amount: 90.0 + company_id: base.main_company + journal_id: account.bank_journal + name: 'Payment: invoice 0' + partner_id: base.res_partner_12 + period_id: account.period_3 + date: !eval time.strftime("%Y-03-10") + type: 'payment' +- + I check voucher state is draft +- + !assert {model: account.voucher, id: account_voucher_0}: + - state == 'draft' +- + I confirm the voucher +- + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_0} +- + I check the entries +- + !python {model: account.voucher}: | + import time + voucher = self.browse(cr, uid, ref('account_voucher_0')) + assert (voucher.state=='posted'), "Voucher is not in posted state: %s" % voucher.state + assert (len(voucher.withholding_move_ids) == 1), "Withholding entry must be one, not %s" % len(voucher.withholding_move_ids) + for move_line in voucher.withholding_move_ids[0].line_id: + if move_line.account_id.id == ref('a_witholding'): + assert (move_line.credit==20.0), "withholding move line credit must be 20 instead of %s" % move_line.credit + assert (move_line.date_maturity==time.strftime("%Y-04-30")), "due date must be %s instead of %s" % (time.strftime("%Y-04-30"),move_line.date_maturity) +- + Finally i will Confirm the state of the invoice is paid +- + !assert {model: account.invoice, id: account_invoice_supplier_0}: + - state == 'paid' From 5272eff2081fa6ccf9689a5ec5224cbd03ea500d Mon Sep 17 00:00:00 2001 From: Lorenzo Battistini Date: Sun, 6 Jul 2014 14:22:40 +0200 Subject: [PATCH 04/89] [REF] Set all the modules of the master branches to "installable": False moves all modules into a __unported__ directory --- l10n_it_withholding_tax/AUTHORS.txt | 2 - l10n_it_withholding_tax/__init__.py | 24 --- l10n_it_withholding_tax/__openerp__.py | 60 ------ l10n_it_withholding_tax/account.py | 204 ------------------ l10n_it_withholding_tax/account_demo.xml | 19 -- l10n_it_withholding_tax/account_view.xml | 71 ------ l10n_it_withholding_tax/i18n/it.mo | Bin 2515 -> 0 bytes l10n_it_withholding_tax/i18n/it.po | 150 ------------- .../test/purchase_payment.yml | 105 --------- 9 files changed, 635 deletions(-) delete mode 100644 l10n_it_withholding_tax/AUTHORS.txt delete mode 100644 l10n_it_withholding_tax/__init__.py delete mode 100644 l10n_it_withholding_tax/__openerp__.py delete mode 100644 l10n_it_withholding_tax/account.py delete mode 100644 l10n_it_withholding_tax/account_demo.xml delete mode 100644 l10n_it_withholding_tax/account_view.xml delete mode 100644 l10n_it_withholding_tax/i18n/it.mo delete mode 100644 l10n_it_withholding_tax/i18n/it.po delete mode 100644 l10n_it_withholding_tax/test/purchase_payment.yml diff --git a/l10n_it_withholding_tax/AUTHORS.txt b/l10n_it_withholding_tax/AUTHORS.txt deleted file mode 100644 index b60a9687c637..000000000000 --- a/l10n_it_withholding_tax/AUTHORS.txt +++ /dev/null @@ -1,2 +0,0 @@ -Lorenzo Battistini -Paolo Chiara diff --git a/l10n_it_withholding_tax/__init__.py b/l10n_it_withholding_tax/__init__.py deleted file mode 100644 index ae9ed0914416..000000000000 --- a/l10n_it_withholding_tax/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2012 Agile Business Group sagl () -# Copyright (C) 2012 Domsense srl () -# Copyright (C) 2012-2013 Associazione OpenERP Italia -# (). -# -# 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 . -# -############################################################################## - -import account diff --git a/l10n_it_withholding_tax/__openerp__.py b/l10n_it_withholding_tax/__openerp__.py deleted file mode 100644 index ba998458109b..000000000000 --- a/l10n_it_withholding_tax/__openerp__.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2012 Agile Business Group sagl () -# Copyright (C) 2012 Domsense srl () -# Copyright (C) 2012-2013 Associazione OpenERP Italia -# (). -# -# 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 . -# -############################################################################## -{ - 'name': "Italian Localisation - Withholding tax", - 'version': '0.2', - 'category': 'Localisation/Italy', - 'description': """ -Ritenute d'acconto sulle fatture fornitore -========================================== - -Per utilizzare il modulo bisogna configurare i campi associati alla company: - - Termine di pagamento della ritenuta - - Conto di debito per le ritenute da versare - - Sezionale che conterrà le registrazioni legate alla ritenuta - -Durante la compilazione di una fattura fornitore con ritenuta d'acconto, l'utente dovrà specificare l'importo della ritenuta. - -Requisiti ---------- -http://wiki.openerp-italia.org/doku.php/area_utente/requisiti/ritenuta_d_acconto - -Howto ------ -http://planet.domsense.com/2012/06/come-registrare-in-openerp-le-fatture-fornitore-con-ritenuta-dacconto/ -""", - 'author': 'OpenERP Italian Community', - 'website': 'http://www.openerp-italia.org', - 'license': 'AGPL-3', - "depends" : ['account_voucher_cash_basis'], - "data" : [ - 'account_view.xml',], - "demo" : [ - 'account_demo.xml', - ], - 'test' : [ - 'test/purchase_payment.yml', - ], - "active": False, - "installable": True -} diff --git a/l10n_it_withholding_tax/account.py b/l10n_it_withholding_tax/account.py deleted file mode 100644 index 9338813558a1..000000000000 --- a/l10n_it_withholding_tax/account.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2012 Agile Business Group sagl () -# Copyright (C) 2012 Domsense srl () -# Copyright (C) 2012-2013 Associazione OpenERP Italia -# (). -# -# 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 fields, orm -from openerp.tools.translate import _ -import decimal_precision as dp - -class res_company(orm.Model): - _inherit = 'res.company' - _columns = { - 'withholding_payment_term_id': fields.many2one('account.payment.term', - 'Withholding tax Payment Term', - help="The withholding tax will have to be paid within this term"), - 'withholding_account_id': fields.many2one('account.account','Withholding account', - help='Payable account used for amount due to tax authority', - domain=[('type', '=', 'payable')]), - 'withholding_journal_id': fields.many2one('account.journal','Withholding journal', - help="Journal used for registration of witholding amounts to be paid"), - 'authority_partner_id': fields.many2one('res.partner', 'Tax Authority Partner'), - } - -class account_config_settings(orm.TransientModel): - _inherit = 'account.config.settings' - _columns = { - 'withholding_payment_term_id': fields.related( - 'company_id', 'withholding_payment_term_id', - type='many2one', - relation="account.payment.term", - string="Withholding tax Payment Term"), - 'withholding_account_id': fields.related( - 'company_id', 'withholding_account_id', - type='many2one', - relation="account.account", - string="Withholding account", - help='Payable account used for amount due to tax authority', - domain=[('type', '=', 'payable')]), - 'withholding_journal_id': fields.related( - 'company_id', 'withholding_journal_id', - type='many2one', - relation="account.journal", - string="Withholding journal", - help='Journal used for registration of witholding amounts to be paid'), - 'authority_partner_id': fields.related( - 'company_id', 'authority_partner_id', - type='many2one', - relation="res.partner", - string="Tax Authority Partner"), - } - - def onchange_company_id(self, cr, uid, ids, company_id, context=None): - res = super(account_config_settings, self).onchange_company_id(cr, uid, ids, company_id, context=context) - if company_id: - company = self.pool.get('res.company').browse(cr, uid, company_id, context=context) - res['value'].update({ - 'withholding_payment_term_id': (company.withholding_payment_term_id - and company.withholding_payment_term_id.id or False), - 'withholding_account_id': (company.withholding_account_id - and company.withholding_account_id.id or False), - 'withholding_journal_id': (company.withholding_journal_id - and company.withholding_journal_id.id or False), - 'authority_partner_id': (company.authority_partner_id - and company.authority_partner_id.id or False), - }) - else: - res['value'].update({ - 'withholding_payment_term_id': False, - 'withholding_account_id': False, - 'withholding_journal_id': False, - 'authority_partner_id': False, - }) - return res - -class account_invoice(orm.Model): - - def _net_pay(self, cr, uid, ids, field_name, arg, context=None): - res = {} - for invoice in self.browse(cr, uid, ids, context): - res[invoice.id] = invoice.amount_total - invoice.withholding_amount - return res - - _inherit = "account.invoice" - - _columns = { - 'withholding_amount': fields.float('Withholding amount', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}), - 'has_withholding': fields.boolean('With withholding tax', readonly=True, states={'draft':[('readonly',False)]}), - 'net_pay': fields.function(_net_pay, string="Net Pay"), - } - -class account_voucher(orm.Model): - _inherit = "account.voucher" - - _columns = { - 'withholding_move_ids': fields.many2many('account.move', 'voucher_withholding_move_rel', 'voucher_id', 'move_id', 'Withholding Tax Entries', readonly=True), - } - - def reconcile_withholding_move(self, cr, uid, invoice, wh_move, context=None): - line_pool=self.pool.get('account.move.line') - rec_ids = [] - for inv_move_line in invoice.move_id.line_id: - if inv_move_line.account_id.type == 'payable' and not inv_move_line.reconcile_id: - rec_ids.append(inv_move_line.id) - for wh_line in wh_move.line_id: - if wh_line.account_id.type == 'payable' and invoice.company_id.withholding_account_id and invoice.company_id.withholding_account_id.id != wh_line.account_id.id and not wh_line.reconcile_id: - rec_ids.append(wh_line.id) - return line_pool.reconcile_partial(cr, uid, rec_ids, type='auto', context=context) - - def action_move_line_create(self, cr, uid, ids, context=None): - res = super(account_voucher,self).action_move_line_create(cr, uid, ids, context) - inv_pool = self.pool.get('account.invoice') - move_pool = self.pool.get('account.move') - tax_pool = self.pool.get('account.tax') - curr_pool = self.pool.get('res.currency') - term_pool = self.pool.get('account.payment.term') - priod_obj = self.pool.get('account.period') - for voucher in self.browse(cr, uid, ids, context): - amounts_by_invoice = super(account_voucher,self).allocated_amounts_grouped_by_invoice(cr, uid,voucher, context) - for inv_id in amounts_by_invoice: - invoice = inv_pool.browse(cr, uid, inv_id, context) - if invoice.withholding_amount: - # only for supplier payments - if voucher.type != 'payment': - raise orm.except_orm(_('Error'), _('Can\'t handle withholding tax with voucher of type other than payment')) - if not invoice.company_id.withholding_account_id: - raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding account') ) - if not invoice.company_id.withholding_payment_term_id: - raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding Payment Term') ) - if not invoice.company_id.withholding_journal_id: - raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding journal') ) - if not invoice.company_id.authority_partner_id: - raise orm.except_orm(_('Error'), _('The company does not have an associated Tax Authority partner') ) - # compute the new amount proportionally to paid amount - new_line_amount = curr_pool.round(cr, uid, voucher.company_id.currency_id, ((amounts_by_invoice[invoice.id]['allocated'] + amounts_by_invoice[invoice.id]['write-off']) / invoice.net_pay) * invoice.withholding_amount) - - # compute the due date - due_list = term_pool.compute( - cr, uid, invoice.company_id.withholding_payment_term_id.id, new_line_amount, - date_ref=voucher.date or invoice.date_invoice, context=context) - if len(due_list) > 1: - raise orm.except_orm(_('Error'), - _('The payment term %s has too many due dates') - % invoice.company_id.withholding_payment_term_id.name) - if len(due_list) == 0: - raise orm.except_orm(_('Error'), - _('The payment term %s does not have due dates') - % invoice.company_id.withholding_payment_term_id.name) - - period_ids = priod_obj.find(cr, uid, dt=voucher.date, context=context) - new_move = { - 'journal_id': invoice.company_id.withholding_journal_id.id, - 'period_id': period_ids and period_ids[0] or False, - 'date': voucher.date, - 'line_id': [ - (0,0,{ - 'name': invoice.number, - 'account_id': invoice.account_id.id, - 'partner_id': invoice.partner_id.id, - 'debit': new_line_amount, - 'credit': 0.0, - }), - (0,0,{ - 'name': _('Payable withholding - ') + invoice.number, - 'account_id': invoice.company_id.withholding_account_id.id, - 'partner_id': invoice.company_id.authority_partner_id.id, - 'debit': 0.0, - 'credit': new_line_amount, - 'date_maturity': due_list[0][0], - }), - ] - } - move_id = self.pool.get('account.move').create(cr, uid, new_move, context=context) - self.reconcile_withholding_move(cr, uid, invoice, move_pool.browse(cr, uid, move_id, context), context) - voucher.write({'withholding_move_ids': [(4, move_id)]}) - return res - - def cancel_voucher(self, cr, uid, ids, context=None): - res = super(account_voucher,self).cancel_voucher(cr, uid, ids, context) - reconcile_pool = self.pool.get('account.move.reconcile') - move_pool = self.pool.get('account.move') - for voucher in self.browse(cr, uid, ids, context=context): - recs = [] - for move in voucher.withholding_move_ids: - move_pool.button_cancel(cr, uid, [move.id]) - move_pool.unlink(cr, uid, [move.id]) - return res diff --git a/l10n_it_withholding_tax/account_demo.xml b/l10n_it_withholding_tax/account_demo.xml deleted file mode 100644 index 26c55edfb9fa..000000000000 --- a/l10n_it_withholding_tax/account_demo.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - X1115 - Withholding tax to pay - - payable - - - - - Tax authority - - - - - diff --git a/l10n_it_withholding_tax/account_view.xml b/l10n_it_withholding_tax/account_view.xml deleted file mode 100644 index f09c3b7c92a3..000000000000 --- a/l10n_it_withholding_tax/account_view.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - view_account_config_settings - account.config.settings - - - - - - - - - - - - - - account.invoice.supplier.form - account.invoice - - - - - - - - - - - - - - - - account.voucher.payment.form.wh.move - account.voucher - - - - - - - - - - - diff --git a/l10n_it_withholding_tax/i18n/it.mo b/l10n_it_withholding_tax/i18n/it.mo deleted file mode 100644 index 2ad76334181ea3809cafde28050b62791084b745..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2515 zcmcJPOK%)S5XT1yB-!vt!Xvzd$|#W~tXXzV0@em18^@MxVrR9PB;tb9JJY+{(Mzea0wiP?C)#v8Sp3Y4EPuLH24q5@ts02 z+&>F)9xEW*T?f~ZO9q}o|NFe$a#DMJ_Y^=avr~c z9MAD%L9hwF0=@xC@GbBz_$v4_$a(w?avlWnINtX_j`subNzj7q|KsZaXW)zIe+9DL z4=zWt@3^Q#!#a0S0$;vplPK_kRlR5QZ zOOK3-<%G1GXI(6j<<3)AQm)m9xuhY6%7w-Y!M4e*7AfUUCe$+)j{C}aE4(tAL*-Pe zOhm>>JMxCT4TVaAUFoSU#sMDDMdG3qX6CM(LkZT!G}c1oaA=jEO`2CLq#znhk{VND zq$|=M2&4)LgmWfVP#~e3b0TAX7LX!ovqL$k0zcH;Tcw73=4z42{lYI47S&#pN2qkp z?Msn`N|2sA&~_kLeM6bh&}M4NO6)&#!Mr>Xbl=e4^2wSXpJcsftk~r}W|IWx&3G&K zsJ{Ovwxd|DZOtti`*14>Z%7V7WzGK{3i5Zlhy&c-aK zX1!5cH`*ibFv9(AVTW(~*N3T4`Xa>xVV(5vT#q)xm6;vK(UUgZKnPqdTC~ztzSd52 zE7EY&*vw&}pei!B>)MO1O67woH*0s4)QK$1%mfRxi<^J%8yXtt6faiP9E39OaaqAXP=EKUWq@T?7h`Mn#|2977sOs`RKY%Ox<)8mR-x6z<^66j zk@wHc`TH+(uE{$%(}Ig@Rr~H=YYU1S6r9NpKyOJi!C7vus{cdj!HGvz$JXLhlv?7j n#tPSo$EITN#W1sOWIQJ{{XNTZI>eP+X;th@De&~yK@0o~W_;8h diff --git a/l10n_it_withholding_tax/i18n/it.po b/l10n_it_withholding_tax/i18n/it.po deleted file mode 100644 index 79515f45df14..000000000000 --- a/l10n_it_withholding_tax/i18n/it.po +++ /dev/null @@ -1,150 +0,0 @@ -# Translation of OpenERP Server. -# This file contains the translation of the following modules: -# * l10n_it_withholding_tax -# -msgid "" -msgstr "" -"Project-Id-Version: OpenERP Server 6.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-12 15:54+0000\n" -"PO-Revision-Date: 2012-10-12 18:02+0100\n" -"Last-Translator: Franco Tampieri \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: \n" - -#. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:90 -#, python-format -msgid "The company does not have an associated Withholding Payment Term" -msgstr "L'Azienda non ha associato nessun Termine di pagamento per le Ritenute" - -#. module: l10n_it_withholding_tax -#: constraint:res.company:0 -msgid "Error! You can not create recursive companies." -msgstr "Errore! Non è possibile creare aziende ricorsive." - -#. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:106 -#, python-format -msgid "The payment term %s does not have due dates" -msgstr "The payment term %s does not have due dates" - -#. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:102 -#, python-format -msgid "The payment term %s has too many due dates" -msgstr "The payment term %s has too many due dates" - -#. module: l10n_it_withholding_tax -#: view:account.voucher:0 -msgid "Withholding tax entries" -msgstr "Voci Tasse Ritenute" - -#. module: l10n_it_withholding_tax -#: field:account.invoice,has_withholding:0 -msgid "With withholding tax" -msgstr "Con tasse ritenute" - -#. module: l10n_it_withholding_tax -#: field:res.company,withholding_payment_term_id:0 -msgid "Withholding tax Payment Term" -msgstr "Termini Pagamento Ritenute" - -#. module: l10n_it_withholding_tax -#: field:res.company,withholding_account_id:0 -msgid "Withholding account" -msgstr "Conto Ritenute" - -#. module: l10n_it_withholding_tax -#: sql_constraint:res.company:0 -msgid "The company name must be unique !" -msgstr "Il nome azienda deve essere unico!" - -#. module: l10n_it_withholding_tax -#: field:account.invoice,net_pay:0 -msgid "Net Pay" -msgstr "Netto da Pagare" - -#. module: l10n_it_withholding_tax -#: model:ir.model,name:l10n_it_withholding_tax.model_res_company -msgid "Companies" -msgstr "Aziende" - -#. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:92 -#, python-format -msgid "The company does not have an associated Withholding journal" -msgstr "L'Azienda non ha un Sezionale associato per le Ritenute" - -#. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:86 -#: code:addons/l10n_it_withholding_tax/account.py:88 -#: code:addons/l10n_it_withholding_tax/account.py:90 -#: code:addons/l10n_it_withholding_tax/account.py:92 -#: code:addons/l10n_it_withholding_tax/account.py:101 -#: code:addons/l10n_it_withholding_tax/account.py:105 -#, python-format -msgid "Error" -msgstr "Errore" - -#. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:86 -#, python-format -msgid "Can't handle withholding tax with voucher of type other than payment" -msgstr "Can't handle withholding tax with voucher of type other than payment" - -#. module: l10n_it_withholding_tax -#: help:res.company,withholding_account_id:0 -msgid "Payable account used for amount due to tax authority" -msgstr "Payable account used for amount due to tax authority" - -#. module: l10n_it_withholding_tax -#: sql_constraint:account.invoice:0 -msgid "Invoice Number must be unique per Company!" -msgstr "Nell'azienda il numero fattura dev'essere univoco!" - -#. module: l10n_it_withholding_tax -#: help:res.company,withholding_journal_id:0 -msgid "Journal used for registration of witholding amounts to be paid" -msgstr "Journal used for registration of witholding amounts to be paid" - -#. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:119 -#, python-format -msgid "Payable withholding - " -msgstr "Ritenute Pagabili - " - -#. module: l10n_it_withholding_tax -#: model:ir.model,name:l10n_it_withholding_tax.model_account_voucher -msgid "Accounting Voucher" -msgstr "Voucher contabile" - -#. module: l10n_it_withholding_tax -#: field:account.invoice,withholding_amount:0 -msgid "Withholding amount" -msgstr "Totale Ritenute" - -#. module: l10n_it_withholding_tax -#: model:ir.model,name:l10n_it_withholding_tax.model_account_invoice -msgid "Invoice" -msgstr "Fattura" - -#. module: l10n_it_withholding_tax -#: field:res.company,withholding_journal_id:0 -msgid "Withholding journal" -msgstr "Sezionale Ritenute" - -#. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:88 -#, python-format -msgid "The company does not have an associated Withholding account" -msgstr "L'Azienda non ha un conto associato per le Ritenute" - -#. module: l10n_it_withholding_tax -#: field:account.voucher,withholding_move_ids:0 -msgid "Withholding Tax Entries" -msgstr "Voci Tasse Ritenute" - diff --git a/l10n_it_withholding_tax/test/purchase_payment.yml b/l10n_it_withholding_tax/test/purchase_payment.yml deleted file mode 100644 index 910a69acad19..000000000000 --- a/l10n_it_withholding_tax/test/purchase_payment.yml +++ /dev/null @@ -1,105 +0,0 @@ -- - I configure the main company -- - !record {model: res.company, id: base.main_company}: - withholding_payment_term_id: account.account_payment_term - withholding_account_id: a_witholding - withholding_journal_id: account.miscellaneous_journal - authority_partner_id: tax_authority -- - In order to test account invoice I create a new supplier invoice -- - I create a Tax Codes -- - !record {model: account.tax.code, id: tax_case}: - name: Tax_case - company_id: base.main_company - sign: 1 -- - I create a Tax -- - !record {model: account.tax, id: tax10}: - name: Tax 10.0 - amount: 10.0 - type: fixed - sequence: 1 - company_id: base.main_company - type_tax_use: all - tax_code_id: tax_case -- - I set the context -- - !context - 'type': 'in_invoice' -- - I create a supplier invoice -- - !record {model: account.invoice, id: account_invoice_supplier_0, view: invoice_supplier_form}: - account_id: account.a_pay - company_id: base.main_company - currency_id: base.EUR - invoice_line: - - account_id: account.a_expense - name: 'Lawyer service' - price_unit: 100.0 - quantity: 1.0 - invoice_line_tax_id: - - tax10 - journal_id: account.expenses_journal - partner_id: base.res_partner_12 - has_withholding: True - withholding_amount: 20.0 -- - I check that Initially supplier invoice state is "Draft" -- - !assert {model: account.invoice, id: account_invoice_supplier_0}: - - state == 'draft' -- - I change the state of invoice to open by clicking Validate button -- - !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_supplier_0} -- - I check that the invoice state is now "Open" and 'Net Pay' is 90 -- - !assert {model: account.invoice, id: account_invoice_supplier_0}: - - state == 'open' - - net_pay == 90.0 -- - I create the voucher of payment with 90 -- - !record {model: account.voucher, id: account_voucher_0, view: account_voucher.view_vendor_payment_form}: - account_id: account.cash - amount: 90.0 - company_id: base.main_company - journal_id: account.bank_journal - name: 'Payment: invoice 0' - partner_id: base.res_partner_12 - period_id: account.period_3 - date: !eval time.strftime("%Y-03-10") - type: 'payment' -- - I check voucher state is draft -- - !assert {model: account.voucher, id: account_voucher_0}: - - state == 'draft' -- - I confirm the voucher -- - !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_0} -- - I check the entries -- - !python {model: account.voucher}: | - import time - voucher = self.browse(cr, uid, ref('account_voucher_0')) - assert (voucher.state=='posted'), "Voucher is not in posted state: %s" % voucher.state - assert (len(voucher.withholding_move_ids) == 1), "Withholding entry must be one, not %s" % len(voucher.withholding_move_ids) - for move_line in voucher.withholding_move_ids[0].line_id: - if move_line.account_id.id == ref('a_witholding'): - assert (move_line.credit==20.0), "withholding move line credit must be 20 instead of %s" % move_line.credit - assert (move_line.date_maturity==time.strftime("%Y-04-30")), "due date must be %s instead of %s" % (time.strftime("%Y-04-30"),move_line.date_maturity) -- - Finally i will Confirm the state of the invoice is paid -- - !assert {model: account.invoice, id: account_invoice_supplier_0}: - - state == 'paid' From aa74fb5df1bf4758933536cae9609b8b93adfd07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Tue, 13 Oct 2015 16:58:13 +0200 Subject: [PATCH 05/89] [MOV] move addons out of __unported__ (they remain not installable) --- l10n_it_withholding_tax/AUTHORS.txt | 2 + l10n_it_withholding_tax/__init__.py | 24 +++ l10n_it_withholding_tax/__openerp__.py | 60 ++++++ l10n_it_withholding_tax/account.py | 204 ++++++++++++++++++ l10n_it_withholding_tax/account_demo.xml | 19 ++ l10n_it_withholding_tax/account_view.xml | 71 ++++++ l10n_it_withholding_tax/i18n/it.mo | Bin 0 -> 2515 bytes l10n_it_withholding_tax/i18n/it.po | 150 +++++++++++++ .../test/purchase_payment.yml | 105 +++++++++ 9 files changed, 635 insertions(+) create mode 100644 l10n_it_withholding_tax/AUTHORS.txt create mode 100644 l10n_it_withholding_tax/__init__.py create mode 100644 l10n_it_withholding_tax/__openerp__.py create mode 100644 l10n_it_withholding_tax/account.py create mode 100644 l10n_it_withholding_tax/account_demo.xml create mode 100644 l10n_it_withholding_tax/account_view.xml create mode 100644 l10n_it_withholding_tax/i18n/it.mo create mode 100644 l10n_it_withholding_tax/i18n/it.po create mode 100644 l10n_it_withholding_tax/test/purchase_payment.yml diff --git a/l10n_it_withholding_tax/AUTHORS.txt b/l10n_it_withholding_tax/AUTHORS.txt new file mode 100644 index 000000000000..b60a9687c637 --- /dev/null +++ b/l10n_it_withholding_tax/AUTHORS.txt @@ -0,0 +1,2 @@ +Lorenzo Battistini +Paolo Chiara diff --git a/l10n_it_withholding_tax/__init__.py b/l10n_it_withholding_tax/__init__.py new file mode 100644 index 000000000000..ae9ed0914416 --- /dev/null +++ b/l10n_it_withholding_tax/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2012 Agile Business Group sagl () +# Copyright (C) 2012 Domsense srl () +# Copyright (C) 2012-2013 Associazione OpenERP Italia +# (). +# +# 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 . +# +############################################################################## + +import account diff --git a/l10n_it_withholding_tax/__openerp__.py b/l10n_it_withholding_tax/__openerp__.py new file mode 100644 index 000000000000..6a02c4af7805 --- /dev/null +++ b/l10n_it_withholding_tax/__openerp__.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2012 Agile Business Group sagl () +# Copyright (C) 2012 Domsense srl () +# Copyright (C) 2012-2013 Associazione OpenERP Italia +# (). +# +# 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 . +# +############################################################################## +{ + 'name': "Italian Localisation - Withholding tax", + 'version': '0.2', + 'category': 'Localisation/Italy', + 'description': """ +Ritenute d'acconto sulle fatture fornitore +========================================== + +Per utilizzare il modulo bisogna configurare i campi associati alla company: + - Termine di pagamento della ritenuta + - Conto di debito per le ritenute da versare + - Sezionale che conterrà le registrazioni legate alla ritenuta + +Durante la compilazione di una fattura fornitore con ritenuta d'acconto, l'utente dovrà specificare l'importo della ritenuta. + +Requisiti +--------- +http://wiki.openerp-italia.org/doku.php/area_utente/requisiti/ritenuta_d_acconto + +Howto +----- +http://planet.domsense.com/2012/06/come-registrare-in-openerp-le-fatture-fornitore-con-ritenuta-dacconto/ +""", + 'author': "OpenERP Italian Community,Odoo Community Association (OCA)", + 'website': 'http://www.openerp-italia.org', + 'license': 'AGPL-3', + "depends" : ['account_voucher_cash_basis'], + "data" : [ + 'account_view.xml',], + "demo" : [ + 'account_demo.xml', + ], + 'test' : [ + 'test/purchase_payment.yml', + ], + "active": False, + 'installable': False +} diff --git a/l10n_it_withholding_tax/account.py b/l10n_it_withholding_tax/account.py new file mode 100644 index 000000000000..9338813558a1 --- /dev/null +++ b/l10n_it_withholding_tax/account.py @@ -0,0 +1,204 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2012 Agile Business Group sagl () +# Copyright (C) 2012 Domsense srl () +# Copyright (C) 2012-2013 Associazione OpenERP Italia +# (). +# +# 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 fields, orm +from openerp.tools.translate import _ +import decimal_precision as dp + +class res_company(orm.Model): + _inherit = 'res.company' + _columns = { + 'withholding_payment_term_id': fields.many2one('account.payment.term', + 'Withholding tax Payment Term', + help="The withholding tax will have to be paid within this term"), + 'withholding_account_id': fields.many2one('account.account','Withholding account', + help='Payable account used for amount due to tax authority', + domain=[('type', '=', 'payable')]), + 'withholding_journal_id': fields.many2one('account.journal','Withholding journal', + help="Journal used for registration of witholding amounts to be paid"), + 'authority_partner_id': fields.many2one('res.partner', 'Tax Authority Partner'), + } + +class account_config_settings(orm.TransientModel): + _inherit = 'account.config.settings' + _columns = { + 'withholding_payment_term_id': fields.related( + 'company_id', 'withholding_payment_term_id', + type='many2one', + relation="account.payment.term", + string="Withholding tax Payment Term"), + 'withholding_account_id': fields.related( + 'company_id', 'withholding_account_id', + type='many2one', + relation="account.account", + string="Withholding account", + help='Payable account used for amount due to tax authority', + domain=[('type', '=', 'payable')]), + 'withholding_journal_id': fields.related( + 'company_id', 'withholding_journal_id', + type='many2one', + relation="account.journal", + string="Withholding journal", + help='Journal used for registration of witholding amounts to be paid'), + 'authority_partner_id': fields.related( + 'company_id', 'authority_partner_id', + type='many2one', + relation="res.partner", + string="Tax Authority Partner"), + } + + def onchange_company_id(self, cr, uid, ids, company_id, context=None): + res = super(account_config_settings, self).onchange_company_id(cr, uid, ids, company_id, context=context) + if company_id: + company = self.pool.get('res.company').browse(cr, uid, company_id, context=context) + res['value'].update({ + 'withholding_payment_term_id': (company.withholding_payment_term_id + and company.withholding_payment_term_id.id or False), + 'withholding_account_id': (company.withholding_account_id + and company.withholding_account_id.id or False), + 'withholding_journal_id': (company.withholding_journal_id + and company.withholding_journal_id.id or False), + 'authority_partner_id': (company.authority_partner_id + and company.authority_partner_id.id or False), + }) + else: + res['value'].update({ + 'withholding_payment_term_id': False, + 'withholding_account_id': False, + 'withholding_journal_id': False, + 'authority_partner_id': False, + }) + return res + +class account_invoice(orm.Model): + + def _net_pay(self, cr, uid, ids, field_name, arg, context=None): + res = {} + for invoice in self.browse(cr, uid, ids, context): + res[invoice.id] = invoice.amount_total - invoice.withholding_amount + return res + + _inherit = "account.invoice" + + _columns = { + 'withholding_amount': fields.float('Withholding amount', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}), + 'has_withholding': fields.boolean('With withholding tax', readonly=True, states={'draft':[('readonly',False)]}), + 'net_pay': fields.function(_net_pay, string="Net Pay"), + } + +class account_voucher(orm.Model): + _inherit = "account.voucher" + + _columns = { + 'withholding_move_ids': fields.many2many('account.move', 'voucher_withholding_move_rel', 'voucher_id', 'move_id', 'Withholding Tax Entries', readonly=True), + } + + def reconcile_withholding_move(self, cr, uid, invoice, wh_move, context=None): + line_pool=self.pool.get('account.move.line') + rec_ids = [] + for inv_move_line in invoice.move_id.line_id: + if inv_move_line.account_id.type == 'payable' and not inv_move_line.reconcile_id: + rec_ids.append(inv_move_line.id) + for wh_line in wh_move.line_id: + if wh_line.account_id.type == 'payable' and invoice.company_id.withholding_account_id and invoice.company_id.withholding_account_id.id != wh_line.account_id.id and not wh_line.reconcile_id: + rec_ids.append(wh_line.id) + return line_pool.reconcile_partial(cr, uid, rec_ids, type='auto', context=context) + + def action_move_line_create(self, cr, uid, ids, context=None): + res = super(account_voucher,self).action_move_line_create(cr, uid, ids, context) + inv_pool = self.pool.get('account.invoice') + move_pool = self.pool.get('account.move') + tax_pool = self.pool.get('account.tax') + curr_pool = self.pool.get('res.currency') + term_pool = self.pool.get('account.payment.term') + priod_obj = self.pool.get('account.period') + for voucher in self.browse(cr, uid, ids, context): + amounts_by_invoice = super(account_voucher,self).allocated_amounts_grouped_by_invoice(cr, uid,voucher, context) + for inv_id in amounts_by_invoice: + invoice = inv_pool.browse(cr, uid, inv_id, context) + if invoice.withholding_amount: + # only for supplier payments + if voucher.type != 'payment': + raise orm.except_orm(_('Error'), _('Can\'t handle withholding tax with voucher of type other than payment')) + if not invoice.company_id.withholding_account_id: + raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding account') ) + if not invoice.company_id.withholding_payment_term_id: + raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding Payment Term') ) + if not invoice.company_id.withholding_journal_id: + raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding journal') ) + if not invoice.company_id.authority_partner_id: + raise orm.except_orm(_('Error'), _('The company does not have an associated Tax Authority partner') ) + # compute the new amount proportionally to paid amount + new_line_amount = curr_pool.round(cr, uid, voucher.company_id.currency_id, ((amounts_by_invoice[invoice.id]['allocated'] + amounts_by_invoice[invoice.id]['write-off']) / invoice.net_pay) * invoice.withholding_amount) + + # compute the due date + due_list = term_pool.compute( + cr, uid, invoice.company_id.withholding_payment_term_id.id, new_line_amount, + date_ref=voucher.date or invoice.date_invoice, context=context) + if len(due_list) > 1: + raise orm.except_orm(_('Error'), + _('The payment term %s has too many due dates') + % invoice.company_id.withholding_payment_term_id.name) + if len(due_list) == 0: + raise orm.except_orm(_('Error'), + _('The payment term %s does not have due dates') + % invoice.company_id.withholding_payment_term_id.name) + + period_ids = priod_obj.find(cr, uid, dt=voucher.date, context=context) + new_move = { + 'journal_id': invoice.company_id.withholding_journal_id.id, + 'period_id': period_ids and period_ids[0] or False, + 'date': voucher.date, + 'line_id': [ + (0,0,{ + 'name': invoice.number, + 'account_id': invoice.account_id.id, + 'partner_id': invoice.partner_id.id, + 'debit': new_line_amount, + 'credit': 0.0, + }), + (0,0,{ + 'name': _('Payable withholding - ') + invoice.number, + 'account_id': invoice.company_id.withholding_account_id.id, + 'partner_id': invoice.company_id.authority_partner_id.id, + 'debit': 0.0, + 'credit': new_line_amount, + 'date_maturity': due_list[0][0], + }), + ] + } + move_id = self.pool.get('account.move').create(cr, uid, new_move, context=context) + self.reconcile_withholding_move(cr, uid, invoice, move_pool.browse(cr, uid, move_id, context), context) + voucher.write({'withholding_move_ids': [(4, move_id)]}) + return res + + def cancel_voucher(self, cr, uid, ids, context=None): + res = super(account_voucher,self).cancel_voucher(cr, uid, ids, context) + reconcile_pool = self.pool.get('account.move.reconcile') + move_pool = self.pool.get('account.move') + for voucher in self.browse(cr, uid, ids, context=context): + recs = [] + for move in voucher.withholding_move_ids: + move_pool.button_cancel(cr, uid, [move.id]) + move_pool.unlink(cr, uid, [move.id]) + return res diff --git a/l10n_it_withholding_tax/account_demo.xml b/l10n_it_withholding_tax/account_demo.xml new file mode 100644 index 000000000000..26c55edfb9fa --- /dev/null +++ b/l10n_it_withholding_tax/account_demo.xml @@ -0,0 +1,19 @@ + + + + + + X1115 + Withholding tax to pay + + payable + + + + + Tax authority + + + + + diff --git a/l10n_it_withholding_tax/account_view.xml b/l10n_it_withholding_tax/account_view.xml new file mode 100644 index 000000000000..f09c3b7c92a3 --- /dev/null +++ b/l10n_it_withholding_tax/account_view.xml @@ -0,0 +1,71 @@ + + + + + + + + view_account_config_settings + account.config.settings + + + + + + + + + + + + + + account.invoice.supplier.form + account.invoice + + + + + + + + + + + + + + + + account.voucher.payment.form.wh.move + account.voucher + + + + + + + + + + + diff --git a/l10n_it_withholding_tax/i18n/it.mo b/l10n_it_withholding_tax/i18n/it.mo new file mode 100644 index 0000000000000000000000000000000000000000..2ad76334181ea3809cafde28050b62791084b745 GIT binary patch literal 2515 zcmcJPOK%)S5XT1yB-!vt!Xvzd$|#W~tXXzV0@em18^@MxVrR9PB;tb9JJY+{(Mzea0wiP?C)#v8Sp3Y4EPuLH24q5@ts02 z+&>F)9xEW*T?f~ZO9q}o|NFe$a#DMJ_Y^=avr~c z9MAD%L9hwF0=@xC@GbBz_$v4_$a(w?avlWnINtX_j`subNzj7q|KsZaXW)zIe+9DL z4=zWt@3^Q#!#a0S0$;vplPK_kRlR5QZ zOOK3-<%G1GXI(6j<<3)AQm)m9xuhY6%7w-Y!M4e*7AfUUCe$+)j{C}aE4(tAL*-Pe zOhm>>JMxCT4TVaAUFoSU#sMDDMdG3qX6CM(LkZT!G}c1oaA=jEO`2CLq#znhk{VND zq$|=M2&4)LgmWfVP#~e3b0TAX7LX!ovqL$k0zcH;Tcw73=4z42{lYI47S&#pN2qkp z?Msn`N|2sA&~_kLeM6bh&}M4NO6)&#!Mr>Xbl=e4^2wSXpJcsftk~r}W|IWx&3G&K zsJ{Ovwxd|DZOtti`*14>Z%7V7WzGK{3i5Zlhy&c-aK zX1!5cH`*ibFv9(AVTW(~*N3T4`Xa>xVV(5vT#q)xm6;vK(UUgZKnPqdTC~ztzSd52 zE7EY&*vw&}pei!B>)MO1O67woH*0s4)QK$1%mfRxi<^J%8yXtt6faiP9E39OaaqAXP=EKUWq@T?7h`Mn#|2977sOs`RKY%Ox<)8mR-x6z<^66j zk@wHc`TH+(uE{$%(}Ig@Rr~H=YYU1S6r9NpKyOJi!C7vus{cdj!HGvz$JXLhlv?7j n#tPSo$EITN#W1sOWIQJ{{XNTZI>eP+X;th@De&~yK@0o~W_;8h literal 0 HcmV?d00001 diff --git a/l10n_it_withholding_tax/i18n/it.po b/l10n_it_withholding_tax/i18n/it.po new file mode 100644 index 000000000000..79515f45df14 --- /dev/null +++ b/l10n_it_withholding_tax/i18n/it.po @@ -0,0 +1,150 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * l10n_it_withholding_tax +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 6.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-10-12 15:54+0000\n" +"PO-Revision-Date: 2012-10-12 18:02+0100\n" +"Last-Translator: Franco Tampieri \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:90 +#, python-format +msgid "The company does not have an associated Withholding Payment Term" +msgstr "L'Azienda non ha associato nessun Termine di pagamento per le Ritenute" + +#. module: l10n_it_withholding_tax +#: constraint:res.company:0 +msgid "Error! You can not create recursive companies." +msgstr "Errore! Non è possibile creare aziende ricorsive." + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:106 +#, python-format +msgid "The payment term %s does not have due dates" +msgstr "The payment term %s does not have due dates" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:102 +#, python-format +msgid "The payment term %s has too many due dates" +msgstr "The payment term %s has too many due dates" + +#. module: l10n_it_withholding_tax +#: view:account.voucher:0 +msgid "Withholding tax entries" +msgstr "Voci Tasse Ritenute" + +#. module: l10n_it_withholding_tax +#: field:account.invoice,has_withholding:0 +msgid "With withholding tax" +msgstr "Con tasse ritenute" + +#. module: l10n_it_withholding_tax +#: field:res.company,withholding_payment_term_id:0 +msgid "Withholding tax Payment Term" +msgstr "Termini Pagamento Ritenute" + +#. module: l10n_it_withholding_tax +#: field:res.company,withholding_account_id:0 +msgid "Withholding account" +msgstr "Conto Ritenute" + +#. module: l10n_it_withholding_tax +#: sql_constraint:res.company:0 +msgid "The company name must be unique !" +msgstr "Il nome azienda deve essere unico!" + +#. module: l10n_it_withholding_tax +#: field:account.invoice,net_pay:0 +msgid "Net Pay" +msgstr "Netto da Pagare" + +#. module: l10n_it_withholding_tax +#: model:ir.model,name:l10n_it_withholding_tax.model_res_company +msgid "Companies" +msgstr "Aziende" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:92 +#, python-format +msgid "The company does not have an associated Withholding journal" +msgstr "L'Azienda non ha un Sezionale associato per le Ritenute" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:86 +#: code:addons/l10n_it_withholding_tax/account.py:88 +#: code:addons/l10n_it_withholding_tax/account.py:90 +#: code:addons/l10n_it_withholding_tax/account.py:92 +#: code:addons/l10n_it_withholding_tax/account.py:101 +#: code:addons/l10n_it_withholding_tax/account.py:105 +#, python-format +msgid "Error" +msgstr "Errore" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:86 +#, python-format +msgid "Can't handle withholding tax with voucher of type other than payment" +msgstr "Can't handle withholding tax with voucher of type other than payment" + +#. module: l10n_it_withholding_tax +#: help:res.company,withholding_account_id:0 +msgid "Payable account used for amount due to tax authority" +msgstr "Payable account used for amount due to tax authority" + +#. module: l10n_it_withholding_tax +#: sql_constraint:account.invoice:0 +msgid "Invoice Number must be unique per Company!" +msgstr "Nell'azienda il numero fattura dev'essere univoco!" + +#. module: l10n_it_withholding_tax +#: help:res.company,withholding_journal_id:0 +msgid "Journal used for registration of witholding amounts to be paid" +msgstr "Journal used for registration of witholding amounts to be paid" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:119 +#, python-format +msgid "Payable withholding - " +msgstr "Ritenute Pagabili - " + +#. module: l10n_it_withholding_tax +#: model:ir.model,name:l10n_it_withholding_tax.model_account_voucher +msgid "Accounting Voucher" +msgstr "Voucher contabile" + +#. module: l10n_it_withholding_tax +#: field:account.invoice,withholding_amount:0 +msgid "Withholding amount" +msgstr "Totale Ritenute" + +#. module: l10n_it_withholding_tax +#: model:ir.model,name:l10n_it_withholding_tax.model_account_invoice +msgid "Invoice" +msgstr "Fattura" + +#. module: l10n_it_withholding_tax +#: field:res.company,withholding_journal_id:0 +msgid "Withholding journal" +msgstr "Sezionale Ritenute" + +#. module: l10n_it_withholding_tax +#: code:addons/l10n_it_withholding_tax/account.py:88 +#, python-format +msgid "The company does not have an associated Withholding account" +msgstr "L'Azienda non ha un conto associato per le Ritenute" + +#. module: l10n_it_withholding_tax +#: field:account.voucher,withholding_move_ids:0 +msgid "Withholding Tax Entries" +msgstr "Voci Tasse Ritenute" + diff --git a/l10n_it_withholding_tax/test/purchase_payment.yml b/l10n_it_withholding_tax/test/purchase_payment.yml new file mode 100644 index 000000000000..910a69acad19 --- /dev/null +++ b/l10n_it_withholding_tax/test/purchase_payment.yml @@ -0,0 +1,105 @@ +- + I configure the main company +- + !record {model: res.company, id: base.main_company}: + withholding_payment_term_id: account.account_payment_term + withholding_account_id: a_witholding + withholding_journal_id: account.miscellaneous_journal + authority_partner_id: tax_authority +- + In order to test account invoice I create a new supplier invoice +- + I create a Tax Codes +- + !record {model: account.tax.code, id: tax_case}: + name: Tax_case + company_id: base.main_company + sign: 1 +- + I create a Tax +- + !record {model: account.tax, id: tax10}: + name: Tax 10.0 + amount: 10.0 + type: fixed + sequence: 1 + company_id: base.main_company + type_tax_use: all + tax_code_id: tax_case +- + I set the context +- + !context + 'type': 'in_invoice' +- + I create a supplier invoice +- + !record {model: account.invoice, id: account_invoice_supplier_0, view: invoice_supplier_form}: + account_id: account.a_pay + company_id: base.main_company + currency_id: base.EUR + invoice_line: + - account_id: account.a_expense + name: 'Lawyer service' + price_unit: 100.0 + quantity: 1.0 + invoice_line_tax_id: + - tax10 + journal_id: account.expenses_journal + partner_id: base.res_partner_12 + has_withholding: True + withholding_amount: 20.0 +- + I check that Initially supplier invoice state is "Draft" +- + !assert {model: account.invoice, id: account_invoice_supplier_0}: + - state == 'draft' +- + I change the state of invoice to open by clicking Validate button +- + !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_supplier_0} +- + I check that the invoice state is now "Open" and 'Net Pay' is 90 +- + !assert {model: account.invoice, id: account_invoice_supplier_0}: + - state == 'open' + - net_pay == 90.0 +- + I create the voucher of payment with 90 +- + !record {model: account.voucher, id: account_voucher_0, view: account_voucher.view_vendor_payment_form}: + account_id: account.cash + amount: 90.0 + company_id: base.main_company + journal_id: account.bank_journal + name: 'Payment: invoice 0' + partner_id: base.res_partner_12 + period_id: account.period_3 + date: !eval time.strftime("%Y-03-10") + type: 'payment' +- + I check voucher state is draft +- + !assert {model: account.voucher, id: account_voucher_0}: + - state == 'draft' +- + I confirm the voucher +- + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_0} +- + I check the entries +- + !python {model: account.voucher}: | + import time + voucher = self.browse(cr, uid, ref('account_voucher_0')) + assert (voucher.state=='posted'), "Voucher is not in posted state: %s" % voucher.state + assert (len(voucher.withholding_move_ids) == 1), "Withholding entry must be one, not %s" % len(voucher.withholding_move_ids) + for move_line in voucher.withholding_move_ids[0].line_id: + if move_line.account_id.id == ref('a_witholding'): + assert (move_line.credit==20.0), "withholding move line credit must be 20 instead of %s" % move_line.credit + assert (move_line.date_maturity==time.strftime("%Y-04-30")), "due date must be %s instead of %s" % (time.strftime("%Y-04-30"),move_line.date_maturity) +- + Finally i will Confirm the state of the invoice is paid +- + !assert {model: account.invoice, id: account_invoice_supplier_0}: + - state == 'paid' From 9cabee0c7a4e960938ffbe215fc32197f1dff09a Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Thu, 6 Oct 2016 14:55:16 +0200 Subject: [PATCH 06/89] [MIG] Rename manifest files --- l10n_it_withholding_tax/{__openerp__.py => __manifest__.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename l10n_it_withholding_tax/{__openerp__.py => __manifest__.py} (100%) diff --git a/l10n_it_withholding_tax/__openerp__.py b/l10n_it_withholding_tax/__manifest__.py similarity index 100% rename from l10n_it_withholding_tax/__openerp__.py rename to l10n_it_withholding_tax/__manifest__.py From 014457870a670964a8fbffeffa20c0d462439f2e Mon Sep 17 00:00:00 2001 From: eLBati Date: Tue, 16 Feb 2016 18:23:26 +0100 Subject: [PATCH 07/89] Adding l10n_it_withholding_tax from http://www.openerpitalia.net/ FIX copyright headers FIX PEP8 IMP description IMP description and copyright FIX PEP8 --- l10n_it_withholding_tax/AUTHORS.txt | 2 - l10n_it_withholding_tax/README.rst | 56 ++ l10n_it_withholding_tax/__init__.py | 25 +- l10n_it_withholding_tax/__manifest__.py | 72 +-- l10n_it_withholding_tax/account.py | 204 ------- l10n_it_withholding_tax/account_demo.xml | 19 - l10n_it_withholding_tax/account_view.xml | 71 --- l10n_it_withholding_tax/i18n/it.mo | Bin 2515 -> 0 bytes l10n_it_withholding_tax/i18n/it.po | 540 ++++++++++++++--- l10n_it_withholding_tax/models/__init__.py | 8 + l10n_it_withholding_tax/models/account.py | 294 +++++++++ l10n_it_withholding_tax/models/voucher.py | 560 ++++++++++++++++++ .../models/withholding_tax.py | 234 ++++++++ .../security/ir.model.access.csv | 14 + .../test/purchase_payment.yml | 105 ---- l10n_it_withholding_tax/views/account.xml | 118 ++++ l10n_it_withholding_tax/views/voucher.xml | 94 +++ .../views/withholding_tax.xml | 242 ++++++++ l10n_it_withholding_tax/wizard/__init__.py | 6 + .../wizard/create_wt_statement.py | 93 +++ .../wizard/create_wt_statement_view.xml | 61 ++ l10n_it_withholding_tax/workflow.xml | 50 ++ 22 files changed, 2306 insertions(+), 562 deletions(-) delete mode 100644 l10n_it_withholding_tax/AUTHORS.txt create mode 100644 l10n_it_withholding_tax/README.rst delete mode 100644 l10n_it_withholding_tax/account.py delete mode 100644 l10n_it_withholding_tax/account_demo.xml delete mode 100644 l10n_it_withholding_tax/account_view.xml delete mode 100644 l10n_it_withholding_tax/i18n/it.mo create mode 100644 l10n_it_withholding_tax/models/__init__.py create mode 100644 l10n_it_withholding_tax/models/account.py create mode 100644 l10n_it_withholding_tax/models/voucher.py create mode 100644 l10n_it_withholding_tax/models/withholding_tax.py create mode 100644 l10n_it_withholding_tax/security/ir.model.access.csv delete mode 100644 l10n_it_withholding_tax/test/purchase_payment.yml create mode 100644 l10n_it_withholding_tax/views/account.xml create mode 100644 l10n_it_withholding_tax/views/voucher.xml create mode 100644 l10n_it_withholding_tax/views/withholding_tax.xml create mode 100644 l10n_it_withholding_tax/wizard/__init__.py create mode 100644 l10n_it_withholding_tax/wizard/create_wt_statement.py create mode 100644 l10n_it_withholding_tax/wizard/create_wt_statement_view.xml create mode 100644 l10n_it_withholding_tax/workflow.xml diff --git a/l10n_it_withholding_tax/AUTHORS.txt b/l10n_it_withholding_tax/AUTHORS.txt deleted file mode 100644 index b60a9687c637..000000000000 --- a/l10n_it_withholding_tax/AUTHORS.txt +++ /dev/null @@ -1,2 +0,0 @@ -Lorenzo Battistini -Paolo Chiara diff --git a/l10n_it_withholding_tax/README.rst b/l10n_it_withholding_tax/README.rst new file mode 100644 index 000000000000..4b062deff819 --- /dev/null +++ b/l10n_it_withholding_tax/README.rst @@ -0,0 +1,56 @@ +.. 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 + +======================= +Italian Withholding Tax +======================= + +Module for Italian Withholding Tax: Ritenute d'acconto + +Gestisce le ritenute sulle fatture e sui pagamenti + +Usage +===== + +* Go to ... + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/122/8.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 +------------ + +* Alessandro Camilli +* Lorenzo Battistini + +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/l10n_it_withholding_tax/__init__.py b/l10n_it_withholding_tax/__init__.py index ae9ed0914416..eea7f1a56c73 100644 --- a/l10n_it_withholding_tax/__init__.py +++ b/l10n_it_withholding_tax/__init__.py @@ -1,24 +1,5 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2012 Agile Business Group sagl () -# Copyright (C) 2012 Domsense srl () -# Copyright (C) 2012-2013 Associazione OpenERP Italia -# (). -# -# 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 . -# -############################################################################## +# Copyright © 2015 Alessandro Camilli () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -import account +from . import models, wizard diff --git a/l10n_it_withholding_tax/__manifest__.py b/l10n_it_withholding_tax/__manifest__.py index 6a02c4af7805..f6c2ba67190b 100644 --- a/l10n_it_withholding_tax/__manifest__.py +++ b/l10n_it_withholding_tax/__manifest__.py @@ -1,60 +1,24 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2012 Agile Business Group sagl () -# Copyright (C) 2012 Domsense srl () -# Copyright (C) 2012-2013 Associazione OpenERP Italia -# (). -# -# 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 . -# -############################################################################## -{ - 'name': "Italian Localisation - Withholding tax", - 'version': '0.2', - 'category': 'Localisation/Italy', - 'description': """ -Ritenute d'acconto sulle fatture fornitore -========================================== - -Per utilizzare il modulo bisogna configurare i campi associati alla company: - - Termine di pagamento della ritenuta - - Conto di debito per le ritenute da versare - - Sezionale che conterrà le registrazioni legate alla ritenuta - -Durante la compilazione di una fattura fornitore con ritenuta d'acconto, l'utente dovrà specificare l'importo della ritenuta. +# Copyright © 2015 Alessandro Camilli () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -Requisiti ---------- -http://wiki.openerp-italia.org/doku.php/area_utente/requisiti/ritenuta_d_acconto - -Howto ------ -http://planet.domsense.com/2012/06/come-registrare-in-openerp-le-fatture-fornitore-con-ritenuta-dacconto/ -""", - 'author': "OpenERP Italian Community,Odoo Community Association (OCA)", - 'website': 'http://www.openerp-italia.org', +{ + 'name': 'Italian Withholding Tax', + 'version': '8.0.2.0.0', + 'category': 'Account', + 'author': 'Openforce di Alessandro Camilli, ' + 'Odoo Community Association (OCA)', + 'website': 'http://www.openforce.it', 'license': 'AGPL-3', - "depends" : ['account_voucher_cash_basis'], - "data" : [ - 'account_view.xml',], - "demo" : [ - 'account_demo.xml', - ], - 'test' : [ - 'test/purchase_payment.yml', + "depends": ['account', 'account_voucher'], + "data": [ + 'views/account.xml', + 'views/voucher.xml', + 'views/withholding_tax.xml', + 'wizard/create_wt_statement_view.xml', + 'security/ir.model.access.csv', + 'workflow.xml', ], "active": False, - 'installable': False + "installable": True } diff --git a/l10n_it_withholding_tax/account.py b/l10n_it_withholding_tax/account.py deleted file mode 100644 index 9338813558a1..000000000000 --- a/l10n_it_withholding_tax/account.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2012 Agile Business Group sagl () -# Copyright (C) 2012 Domsense srl () -# Copyright (C) 2012-2013 Associazione OpenERP Italia -# (). -# -# 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 fields, orm -from openerp.tools.translate import _ -import decimal_precision as dp - -class res_company(orm.Model): - _inherit = 'res.company' - _columns = { - 'withholding_payment_term_id': fields.many2one('account.payment.term', - 'Withholding tax Payment Term', - help="The withholding tax will have to be paid within this term"), - 'withholding_account_id': fields.many2one('account.account','Withholding account', - help='Payable account used for amount due to tax authority', - domain=[('type', '=', 'payable')]), - 'withholding_journal_id': fields.many2one('account.journal','Withholding journal', - help="Journal used for registration of witholding amounts to be paid"), - 'authority_partner_id': fields.many2one('res.partner', 'Tax Authority Partner'), - } - -class account_config_settings(orm.TransientModel): - _inherit = 'account.config.settings' - _columns = { - 'withholding_payment_term_id': fields.related( - 'company_id', 'withholding_payment_term_id', - type='many2one', - relation="account.payment.term", - string="Withholding tax Payment Term"), - 'withholding_account_id': fields.related( - 'company_id', 'withholding_account_id', - type='many2one', - relation="account.account", - string="Withholding account", - help='Payable account used for amount due to tax authority', - domain=[('type', '=', 'payable')]), - 'withholding_journal_id': fields.related( - 'company_id', 'withholding_journal_id', - type='many2one', - relation="account.journal", - string="Withholding journal", - help='Journal used for registration of witholding amounts to be paid'), - 'authority_partner_id': fields.related( - 'company_id', 'authority_partner_id', - type='many2one', - relation="res.partner", - string="Tax Authority Partner"), - } - - def onchange_company_id(self, cr, uid, ids, company_id, context=None): - res = super(account_config_settings, self).onchange_company_id(cr, uid, ids, company_id, context=context) - if company_id: - company = self.pool.get('res.company').browse(cr, uid, company_id, context=context) - res['value'].update({ - 'withholding_payment_term_id': (company.withholding_payment_term_id - and company.withholding_payment_term_id.id or False), - 'withholding_account_id': (company.withholding_account_id - and company.withholding_account_id.id or False), - 'withholding_journal_id': (company.withholding_journal_id - and company.withholding_journal_id.id or False), - 'authority_partner_id': (company.authority_partner_id - and company.authority_partner_id.id or False), - }) - else: - res['value'].update({ - 'withholding_payment_term_id': False, - 'withholding_account_id': False, - 'withholding_journal_id': False, - 'authority_partner_id': False, - }) - return res - -class account_invoice(orm.Model): - - def _net_pay(self, cr, uid, ids, field_name, arg, context=None): - res = {} - for invoice in self.browse(cr, uid, ids, context): - res[invoice.id] = invoice.amount_total - invoice.withholding_amount - return res - - _inherit = "account.invoice" - - _columns = { - 'withholding_amount': fields.float('Withholding amount', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}), - 'has_withholding': fields.boolean('With withholding tax', readonly=True, states={'draft':[('readonly',False)]}), - 'net_pay': fields.function(_net_pay, string="Net Pay"), - } - -class account_voucher(orm.Model): - _inherit = "account.voucher" - - _columns = { - 'withholding_move_ids': fields.many2many('account.move', 'voucher_withholding_move_rel', 'voucher_id', 'move_id', 'Withholding Tax Entries', readonly=True), - } - - def reconcile_withholding_move(self, cr, uid, invoice, wh_move, context=None): - line_pool=self.pool.get('account.move.line') - rec_ids = [] - for inv_move_line in invoice.move_id.line_id: - if inv_move_line.account_id.type == 'payable' and not inv_move_line.reconcile_id: - rec_ids.append(inv_move_line.id) - for wh_line in wh_move.line_id: - if wh_line.account_id.type == 'payable' and invoice.company_id.withholding_account_id and invoice.company_id.withholding_account_id.id != wh_line.account_id.id and not wh_line.reconcile_id: - rec_ids.append(wh_line.id) - return line_pool.reconcile_partial(cr, uid, rec_ids, type='auto', context=context) - - def action_move_line_create(self, cr, uid, ids, context=None): - res = super(account_voucher,self).action_move_line_create(cr, uid, ids, context) - inv_pool = self.pool.get('account.invoice') - move_pool = self.pool.get('account.move') - tax_pool = self.pool.get('account.tax') - curr_pool = self.pool.get('res.currency') - term_pool = self.pool.get('account.payment.term') - priod_obj = self.pool.get('account.period') - for voucher in self.browse(cr, uid, ids, context): - amounts_by_invoice = super(account_voucher,self).allocated_amounts_grouped_by_invoice(cr, uid,voucher, context) - for inv_id in amounts_by_invoice: - invoice = inv_pool.browse(cr, uid, inv_id, context) - if invoice.withholding_amount: - # only for supplier payments - if voucher.type != 'payment': - raise orm.except_orm(_('Error'), _('Can\'t handle withholding tax with voucher of type other than payment')) - if not invoice.company_id.withholding_account_id: - raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding account') ) - if not invoice.company_id.withholding_payment_term_id: - raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding Payment Term') ) - if not invoice.company_id.withholding_journal_id: - raise orm.except_orm(_('Error'), _('The company does not have an associated Withholding journal') ) - if not invoice.company_id.authority_partner_id: - raise orm.except_orm(_('Error'), _('The company does not have an associated Tax Authority partner') ) - # compute the new amount proportionally to paid amount - new_line_amount = curr_pool.round(cr, uid, voucher.company_id.currency_id, ((amounts_by_invoice[invoice.id]['allocated'] + amounts_by_invoice[invoice.id]['write-off']) / invoice.net_pay) * invoice.withholding_amount) - - # compute the due date - due_list = term_pool.compute( - cr, uid, invoice.company_id.withholding_payment_term_id.id, new_line_amount, - date_ref=voucher.date or invoice.date_invoice, context=context) - if len(due_list) > 1: - raise orm.except_orm(_('Error'), - _('The payment term %s has too many due dates') - % invoice.company_id.withholding_payment_term_id.name) - if len(due_list) == 0: - raise orm.except_orm(_('Error'), - _('The payment term %s does not have due dates') - % invoice.company_id.withholding_payment_term_id.name) - - period_ids = priod_obj.find(cr, uid, dt=voucher.date, context=context) - new_move = { - 'journal_id': invoice.company_id.withholding_journal_id.id, - 'period_id': period_ids and period_ids[0] or False, - 'date': voucher.date, - 'line_id': [ - (0,0,{ - 'name': invoice.number, - 'account_id': invoice.account_id.id, - 'partner_id': invoice.partner_id.id, - 'debit': new_line_amount, - 'credit': 0.0, - }), - (0,0,{ - 'name': _('Payable withholding - ') + invoice.number, - 'account_id': invoice.company_id.withholding_account_id.id, - 'partner_id': invoice.company_id.authority_partner_id.id, - 'debit': 0.0, - 'credit': new_line_amount, - 'date_maturity': due_list[0][0], - }), - ] - } - move_id = self.pool.get('account.move').create(cr, uid, new_move, context=context) - self.reconcile_withholding_move(cr, uid, invoice, move_pool.browse(cr, uid, move_id, context), context) - voucher.write({'withholding_move_ids': [(4, move_id)]}) - return res - - def cancel_voucher(self, cr, uid, ids, context=None): - res = super(account_voucher,self).cancel_voucher(cr, uid, ids, context) - reconcile_pool = self.pool.get('account.move.reconcile') - move_pool = self.pool.get('account.move') - for voucher in self.browse(cr, uid, ids, context=context): - recs = [] - for move in voucher.withholding_move_ids: - move_pool.button_cancel(cr, uid, [move.id]) - move_pool.unlink(cr, uid, [move.id]) - return res diff --git a/l10n_it_withholding_tax/account_demo.xml b/l10n_it_withholding_tax/account_demo.xml deleted file mode 100644 index 26c55edfb9fa..000000000000 --- a/l10n_it_withholding_tax/account_demo.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - X1115 - Withholding tax to pay - - payable - - - - - Tax authority - - - - - diff --git a/l10n_it_withholding_tax/account_view.xml b/l10n_it_withholding_tax/account_view.xml deleted file mode 100644 index f09c3b7c92a3..000000000000 --- a/l10n_it_withholding_tax/account_view.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - view_account_config_settings - account.config.settings - - - - - - - - - - - - - - account.invoice.supplier.form - account.invoice - - - - - - - - - - - - - - - - account.voucher.payment.form.wh.move - account.voucher - - - - - - - - - - - diff --git a/l10n_it_withholding_tax/i18n/it.mo b/l10n_it_withholding_tax/i18n/it.mo deleted file mode 100644 index 2ad76334181ea3809cafde28050b62791084b745..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2515 zcmcJPOK%)S5XT1yB-!vt!Xvzd$|#W~tXXzV0@em18^@MxVrR9PB;tb9JJY+{(Mzea0wiP?C)#v8Sp3Y4EPuLH24q5@ts02 z+&>F)9xEW*T?f~ZO9q}o|NFe$a#DMJ_Y^=avr~c z9MAD%L9hwF0=@xC@GbBz_$v4_$a(w?avlWnINtX_j`subNzj7q|KsZaXW)zIe+9DL z4=zWt@3^Q#!#a0S0$;vplPK_kRlR5QZ zOOK3-<%G1GXI(6j<<3)AQm)m9xuhY6%7w-Y!M4e*7AfUUCe$+)j{C}aE4(tAL*-Pe zOhm>>JMxCT4TVaAUFoSU#sMDDMdG3qX6CM(LkZT!G}c1oaA=jEO`2CLq#znhk{VND zq$|=M2&4)LgmWfVP#~e3b0TAX7LX!ovqL$k0zcH;Tcw73=4z42{lYI47S&#pN2qkp z?Msn`N|2sA&~_kLeM6bh&}M4NO6)&#!Mr>Xbl=e4^2wSXpJcsftk~r}W|IWx&3G&K zsJ{Ovwxd|DZOtti`*14>Z%7V7WzGK{3i5Zlhy&c-aK zX1!5cH`*ibFv9(AVTW(~*N3T4`Xa>xVV(5vT#q)xm6;vK(UUgZKnPqdTC~ztzSd52 zE7EY&*vw&}pei!B>)MO1O67woH*0s4)QK$1%mfRxi<^J%8yXtt6faiP9E39OaaqAXP=EKUWq@T?7h`Mn#|2977sOs`RKY%Ox<)8mR-x6z<^66j zk@wHc`TH+(uE{$%(}Ig@Rr~H=YYU1S6r9NpKyOJi!C7vus{cdj!HGvz$JXLhlv?7j n#tPSo$EITN#W1sOWIQJ{{XNTZI>eP+X;th@De&~yK@0o~W_;8h diff --git a/l10n_it_withholding_tax/i18n/it.po b/l10n_it_withholding_tax/i18n/it.po index 79515f45df14..24c5adccb2cd 100644 --- a/l10n_it_withholding_tax/i18n/it.po +++ b/l10n_it_withholding_tax/i18n/it.po @@ -1,150 +1,520 @@ -# Translation of OpenERP Server. +# Translation of Odoo Server. # This file contains the translation of the following modules: # * l10n_it_withholding_tax # msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 6.1\n" +"Project-Id-Version: Odoo Server 8.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-12 15:54+0000\n" -"PO-Revision-Date: 2012-10-12 18:02+0100\n" -"Last-Translator: Franco Tampieri \n" +"POT-Creation-Date: 2015-10-19 17:00+0000\n" +"PO-Revision-Date: 2015-10-19 17:00+0000\n" +"Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" +"Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#: model:ir.model,name:l10n_it_withholding_tax.model_account_move #. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:90 -#, python-format -msgid "The company does not have an associated Withholding Payment Term" -msgstr "L'Azienda non ha associato nessun Termine di pagamento per le Ritenute" +msgid "Account Entry" +msgstr "Registrazione Contabile" +#: field:withholding.tax.move,account_move_id:0 +#: field:withholding.tax.wizard.create.statement,move_id:0 #. module: l10n_it_withholding_tax -#: constraint:res.company:0 -msgid "Error! You can not create recursive companies." -msgstr "Errore! Non è possibile creare aziende ricorsive." +msgid "Account Move" +msgstr "Registrazione" +#: field:withholding.tax.move,move_line_id:0 +#: field:withholding.tax.wizard.create.statement,wt_account_move_line_id:0 #. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:106 -#, python-format -msgid "The payment term %s does not have due dates" -msgstr "The payment term %s does not have due dates" +msgid "Account Move line" +msgstr "Linee Registrazione" + +#: field:withholding.tax,account_payable_id:0 +#. module: l10n_it_withholding_tax +msgid "Account Payable" +msgstr "Conto di Debito" + +#: field:withholding.tax,account_receivable_id:0 +#. module: l10n_it_withholding_tax +msgid "Account Receivable" +msgstr "Conto di Credito" + +#: field:withholding.tax.voucher.line,voucher_line_id:0 +#. module: l10n_it_withholding_tax +msgid "Account Voucher Line" +msgstr "Account Voucher Line" + +#: field:withholding.tax.statement,move_id:0 +#. module: l10n_it_withholding_tax +msgid "Account move" +msgstr "Registrazione Contabile" + +#: model:ir.model,name:l10n_it_withholding_tax.model_account_voucher +#. module: l10n_it_withholding_tax +msgid "Accounting Voucher" +msgstr "Voucher contabile" + +#: field:withholding.tax,active:0 +#. module: l10n_it_withholding_tax +msgid "Active" +msgstr "Attivo" + +#: field:withholding.tax.move,amount:0 +#: field:withholding.tax.voucher.line,amount:0 +#. module: l10n_it_withholding_tax +msgid "Amount" +msgstr "Importo" + +#: field:account.invoice.withholding.tax,base:0 +#: field:withholding.tax.statement,base:0 +#: field:withholding.tax.wizard.create.statement,base:0 +#. module: l10n_it_withholding_tax +msgid "Base" +msgstr "Imponibile" + +#: field:withholding.tax.rate,base:0 +#. module: l10n_it_withholding_tax +msgid "Base Coeff." +msgstr "Coeff. Imponibile" + +#: view:withholding.tax.wizard.create.statement:l10n_it_withholding_tax.wt_wizard_create_statement +#. module: l10n_it_withholding_tax +msgid "Cancel" +msgstr "Annulla" + +#: field:withholding.tax,certification:0 +#. module: l10n_it_withholding_tax +msgid "Certification" +msgstr "Da Certificare" + +#: view:withholding.tax.wizard.create.statement:l10n_it_withholding_tax.wt_wizard_create_statement +#. module: l10n_it_withholding_tax +msgid "Create" +msgstr "Crea" + +#: model:ir.actions.act_window,name:l10n_it_withholding_tax.wt_wizard_create_statement_action +#: view:withholding.tax.wizard.create.statement:l10n_it_withholding_tax.wt_wizard_create_statement +#. module: l10n_it_withholding_tax +msgid "Create Withholding Tax Statement" +msgstr "Crea Movimento di Ritenuta" + +#: field:account.invoice.withholding.tax,create_uid:0 +#: field:withholding.tax,create_uid:0 +#: field:withholding.tax.move,create_uid:0 +#: field:withholding.tax.rate,create_uid:0 +#: field:withholding.tax.statement,create_uid:0 +#: field:withholding.tax.voucher.line,create_uid:0 +#: field:withholding.tax.wizard.create.statement,create_uid:0 +#. module: l10n_it_withholding_tax +msgid "Created by" +msgstr "Created by" +#: field:account.invoice.withholding.tax,create_date:0 +#: field:withholding.tax,create_date:0 +#: field:withholding.tax.move,create_date:0 +#: field:withholding.tax.rate,create_date:0 +#: field:withholding.tax.statement,create_date:0 +#: field:withholding.tax.voucher.line,create_date:0 +#: field:withholding.tax.wizard.create.statement,create_date:0 +#. module: l10n_it_withholding_tax +msgid "Created on" +msgstr "Created on" + +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_search +#: view:withholding.tax.statement:l10n_it_withholding_tax.view_withholding_tax_statement_search +#: field:withholding.tax.statement,date:0 +#: field:withholding.tax.wizard.create.statement,date:0 +#. module: l10n_it_withholding_tax +msgid "Date" +msgstr "Data" + +#: field:withholding.tax.move,date:0 +#. module: l10n_it_withholding_tax +msgid "Date Competence" +msgstr "Data Competenza" + +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_search +#: field:withholding.tax.move,date_maturity:0 +#. module: l10n_it_withholding_tax +msgid "Date Maturity" +msgstr "Data Scadenza" + +#: field:withholding.tax.rate,date_start:0 +#. module: l10n_it_withholding_tax +msgid "Date Start" +msgstr "Data inizio" + +#: field:withholding.tax.rate,date_stop:0 +#. module: l10n_it_withholding_tax +msgid "Date Stop" +msgstr "Data fine" + +#: view:withholding.tax.wizard.create.statement:l10n_it_withholding_tax.wt_wizard_create_statement +#. module: l10n_it_withholding_tax +msgid "Document" +msgstr "Documento" + +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_search +#: selection:withholding.tax.move,state:0 +#. module: l10n_it_withholding_tax +msgid "Due" +msgstr "Da pagare" + +#: code:addons/l10n_it_withholding_tax/models/withholding_tax.py:129 #. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:102 #, python-format -msgid "The payment term %s has too many due dates" -msgstr "The payment term %s has too many due dates" +msgid "Error! You cannot have 2 pricelist versions that overlap!" +msgstr "Errore! I periodi si sovrappongono" + +#: model:ir.model,name:l10n_it_withholding_tax.model_account_fiscal_position +#. module: l10n_it_withholding_tax +msgid "Fiscal Position" +msgstr "Posizione fiscale" + +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_search +#: view:withholding.tax.statement:l10n_it_withholding_tax.view_withholding_tax_statement_search +#. module: l10n_it_withholding_tax +msgid "Group By..." +msgstr "Group By..." + +#: field:account.invoice.withholding.tax,id:0 +#: field:withholding.tax,id:0 +#: field:withholding.tax.move,id:0 +#: field:withholding.tax.rate,id:0 +#: field:withholding.tax.statement,id:0 +#: field:withholding.tax.voucher.line,id:0 +#: field:withholding.tax.wizard.create.statement,id:0 +#. module: l10n_it_withholding_tax +msgid "ID" +msgstr "ID" + +#: field:account.invoice.withholding.tax,invoice_id:0 +#: model:ir.model,name:l10n_it_withholding_tax.model_account_invoice +#: field:withholding.tax.statement,invoice_id:0 +#. module: l10n_it_withholding_tax +msgid "Invoice" +msgstr "Fattura" + +#: model:ir.model,name:l10n_it_withholding_tax.model_account_invoice_line +#. module: l10n_it_withholding_tax +msgid "Invoice Line" +msgstr "Righe Fattura" + +#: model:ir.model,name:l10n_it_withholding_tax.model_account_invoice_withholding_tax +#. module: l10n_it_withholding_tax +msgid "Invoice Withholding Tax Line" +msgstr "Invoice Withholding Tax Line" + +#: model:ir.model,name:l10n_it_withholding_tax.model_account_move_line +#. module: l10n_it_withholding_tax +msgid "Journal Items" +msgstr "Voci sezionale" +#: field:account.invoice.withholding.tax,write_uid:0 +#: field:withholding.tax,write_uid:0 +#: field:withholding.tax.move,write_uid:0 +#: field:withholding.tax.rate,write_uid:0 +#: field:withholding.tax.statement,write_uid:0 +#: field:withholding.tax.voucher.line,write_uid:0 +#: field:withholding.tax.wizard.create.statement,write_uid:0 #. module: l10n_it_withholding_tax -#: view:account.voucher:0 -msgid "Withholding tax entries" -msgstr "Voci Tasse Ritenute" +msgid "Last Updated by" +msgstr "Last Updated by" +#: field:account.invoice.withholding.tax,write_date:0 +#: field:withholding.tax,write_date:0 +#: field:withholding.tax.move,write_date:0 +#: field:withholding.tax.rate,write_date:0 +#: field:withholding.tax.statement,write_date:0 +#: field:withholding.tax.voucher.line,write_date:0 +#: field:withholding.tax.wizard.create.statement,write_date:0 #. module: l10n_it_withholding_tax -#: field:account.invoice,has_withholding:0 -msgid "With withholding tax" -msgstr "Con tasse ritenute" +msgid "Last Updated on" +msgstr "Last Updated on" +#: field:withholding.tax.statement,move_ids:0 #. module: l10n_it_withholding_tax -#: field:res.company,withholding_payment_term_id:0 -msgid "Withholding tax Payment Term" -msgstr "Termini Pagamento Ritenute" +msgid "Moves" +msgstr "Movimenti" +#: field:withholding.tax,name:0 #. module: l10n_it_withholding_tax -#: field:res.company,withholding_account_id:0 -msgid "Withholding account" -msgstr "Conto Ritenute" +msgid "Name" +msgstr "Nome" +#: field:account.invoice,amount_net_pay:0 #. module: l10n_it_withholding_tax -#: sql_constraint:res.company:0 -msgid "The company name must be unique !" -msgstr "Il nome azienda deve essere unico!" +msgid "Net To Pay" +msgstr "Netto a Pagare" +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_form +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_search +#: selection:withholding.tax.move,state:0 #. module: l10n_it_withholding_tax -#: field:account.invoice,net_pay:0 -msgid "Net Pay" -msgstr "Netto da Pagare" +msgid "Paid" +msgstr "Pagata" +#: field:withholding.tax.move,partner_id:0 +#: field:withholding.tax.statement,partner_id:0 +#: field:withholding.tax.wizard.create.statement,partner_id:0 #. module: l10n_it_withholding_tax -#: model:ir.model,name:l10n_it_withholding_tax.model_res_company -msgid "Companies" -msgstr "Aziende" +msgid "Partner" +msgstr "Partner" +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_search +#: view:withholding.tax.statement:l10n_it_withholding_tax.view_withholding_tax_statement_search +#. module: l10n_it_withholding_tax +msgid "Partners" +msgstr "Partners" + +#: field:withholding.tax,payment_term:0 +#. module: l10n_it_withholding_tax +msgid "Payment Terms" +msgstr "Termini di pagamento" + +#: view:withholding.tax:l10n_it_withholding_tax.view_withholding_tax_form +#: field:withholding.tax,rate_ids:0 +#. module: l10n_it_withholding_tax +msgid "Rates" +msgstr "Validità aliquote" + +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_form +#. module: l10n_it_withholding_tax +msgid "Set to Draft" +msgstr "Imposta a Bozza" + +#: field:withholding.tax.move,statement_id:0 +#. module: l10n_it_withholding_tax +msgid "Statement" +msgstr "Statement" + +#: field:withholding.tax.move,state:0 +#. module: l10n_it_withholding_tax +msgid "Status" +msgstr "Stato" + +#: field:account.invoice.withholding.tax,tax:0 +#: field:withholding.tax.statement,tax:0 +#: field:withholding.tax.wizard.create.statement,tax:0 +#. module: l10n_it_withholding_tax +msgid "Tax" +msgstr "Importo" + +#: field:withholding.tax.rate,tax:0 +#. module: l10n_it_withholding_tax +msgid "Tax %" +msgstr "Tax %" + +#: field:withholding.tax,comment:0 +#: field:withholding.tax.rate,comment:0 +#. module: l10n_it_withholding_tax +msgid "Text" +msgstr "Text" + +#: code:addons/l10n_it_withholding_tax/wizard/create_wt_statement.py:46 #. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:92 #, python-format -msgid "The company does not have an associated Withholding journal" -msgstr "L'Azienda non ha un Sezionale associato per le Ritenute" +msgid "This Move is already present in the WT" +msgstr "Questa registrazione è già presente tra i movimenti di ritenuta" + +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_tree +#. module: l10n_it_withholding_tax +msgid "Tot" +msgstr "Tot" + +#: view:withholding.tax.statement:l10n_it_withholding_tax.view_withholding_statement_tree +#. module: l10n_it_withholding_tax +msgid "Tot Amount" +msgstr "Importo totale" + +#: view:withholding.tax.statement:l10n_it_withholding_tax.view_withholding_statement_tree +#. module: l10n_it_withholding_tax +msgid "Tot Amount Paid" +msgstr "Tot Importo Pagato" + +#: view:withholding.tax.statement:l10n_it_withholding_tax.view_withholding_statement_tree +#. module: l10n_it_withholding_tax +msgid "Tot Base" +msgstr "Tot Imponibile" + +#: view:account.voucher:l10n_it_withholding_tax.view_withholding_voucher_payment_supplier_form +#: view:account.voucher:l10n_it_withholding_tax.view_withholding_voucher_vendor_receipt_form +#. module: l10n_it_withholding_tax +msgid "Total Amount" +msgstr "Importo totale" + +#: help:withholding.tax.move,move_line_id:0 +#. module: l10n_it_withholding_tax +msgid "Used from trace WT from other parts(BS)" +msgstr "Used from trace WT from other parts(BS)" + +#: model:ir.model,name:l10n_it_withholding_tax.model_account_voucher_line +#. module: l10n_it_withholding_tax +msgid "Voucher Lines" +msgstr "Righe voucher" + +#: field:withholding.tax.move,wt_voucher_line_id:0 +#. module: l10n_it_withholding_tax +msgid "WT Account Voucher Line" +msgstr "WT Account Voucher Line" + +#: model:ir.ui.menu,name:l10n_it_withholding_tax.menu_withholding_tax_move +#. module: l10n_it_withholding_tax +msgid "WT Moves" +msgstr "Voci ritenuta" + +#: model:ir.ui.menu,name:l10n_it_withholding_tax.menu_withholding_tax_statement +#. module: l10n_it_withholding_tax +msgid "WT Statements" +msgstr "Situazione Ritenute" + +#: field:withholding.tax.statement,amount:0 +#: field:withholding.tax.wizard.create.statement,amount:0 +#. module: l10n_it_withholding_tax +msgid "WT amount" +msgstr "Importo Ritenuta" + +#: field:withholding.tax.statement,amount_paid:0 +#. module: l10n_it_withholding_tax +msgid "WT amount paid" +msgstr "Ritenuta Versata" +#: code:addons/l10n_it_withholding_tax/wizard/create_wt_statement.py:39 +#: code:addons/l10n_it_withholding_tax/wizard/create_wt_statement.py:45 #. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:86 -#: code:addons/l10n_it_withholding_tax/account.py:88 -#: code:addons/l10n_it_withholding_tax/account.py:90 -#: code:addons/l10n_it_withholding_tax/account.py:92 -#: code:addons/l10n_it_withholding_tax/account.py:101 -#: code:addons/l10n_it_withholding_tax/account.py:105 #, python-format -msgid "Error" -msgstr "Errore" +msgid "Warning!" +msgstr "Warning!" +#: code:addons/l10n_it_withholding_tax/models/withholding_tax.py:248 #. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:86 #, python-format -msgid "Can't handle withholding tax with voucher of type other than payment" -msgstr "Can't handle withholding tax with voucher of type other than payment" +msgid "Warning! You cannot delet move linked to voucher.You must before delete the voucher." +msgstr "Warning! You cannot delet move linked to voucher.You must before delete the voucher." + +#: field:account.voucher,website_message_ids:0 +#. module: l10n_it_withholding_tax +msgid "Website Messages" +msgstr "Messaggio sito" + +#: help:account.voucher,website_message_ids:0 +#. module: l10n_it_withholding_tax +msgid "Website communication history" +msgstr "Storico comunicazione sito" + +#: view:account.fiscal.position:l10n_it_withholding_tax.view_withholding_tax_fiscal_position_form +#: field:account.fiscal.position,withholding_tax_ids:0 +#: field:account.invoice,withholding_tax:0 +#: field:account.invoice,withholding_tax_line:0 +#: model:ir.model,name:l10n_it_withholding_tax.model_withholding_tax +#: model:ir.ui.menu,name:l10n_it_withholding_tax.menu_withholding_tax +#: view:withholding.tax:l10n_it_withholding_tax.view_withholding_tax_form +#: view:withholding.tax:l10n_it_withholding_tax.view_withholding_tax_tree +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_search +#: field:withholding.tax.move,withholding_tax_id:0 +#: field:withholding.tax.rate,withholding_tax_id:0 +#: view:withholding.tax.statement:l10n_it_withholding_tax.view_withholding_tax_statement_search +#: field:withholding.tax.statement,withholding_tax_id:0 +#: field:withholding.tax.voucher.line,withholding_tax_id:0 +#: view:withholding.tax.wizard.create.statement:l10n_it_withholding_tax.wt_wizard_create_statement +#: field:withholding.tax.wizard.create.statement,withholding_tax_id:0 +#. module: l10n_it_withholding_tax +msgid "Withholding Tax" +msgstr "Ritenuta" + +#: field:account.move.line,withholding_tax_amount:0 +#: field:account.voucher.line,amount_withholding_tax:0 +#. module: l10n_it_withholding_tax +msgid "Withholding Tax Amount" +msgstr "Ritenuta D'Acconto Allocazione" +#: field:account.voucher.line,amount_residual_withholding_tax:0 #. module: l10n_it_withholding_tax -#: help:res.company,withholding_account_id:0 -msgid "Payable account used for amount due to tax authority" -msgstr "Payable account used for amount due to tax authority" +msgid "Withholding Tax Amount Residual" +msgstr "Ritenuta Residuo" +#: field:account.voucher.line,withholding_tax_line_ids:0 #. module: l10n_it_withholding_tax -#: sql_constraint:account.invoice:0 -msgid "Invoice Number must be unique per Company!" -msgstr "Nell'azienda il numero fattura dev'essere univoco!" +msgid "Withholding Tax Lines" +msgstr "Ritenuta D'acconto linee" +#: model:ir.model,name:l10n_it_withholding_tax.model_withholding_tax_move +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_form +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_search +#: view:withholding.tax.move:l10n_it_withholding_tax.view_withholding_move_tree #. module: l10n_it_withholding_tax -#: help:res.company,withholding_journal_id:0 -msgid "Journal used for registration of witholding amounts to be paid" -msgstr "Journal used for registration of witholding amounts to be paid" +msgid "Withholding Tax Move" +msgstr "Voci ritenuta" +#: field:account.voucher.line,amount_original_withholding_tax:0 +#. module: l10n_it_withholding_tax +msgid "Withholding Tax Original" +msgstr "Ritenuta Importo originario" + +#: model:ir.model,name:l10n_it_withholding_tax.model_withholding_tax_rate +#. module: l10n_it_withholding_tax +msgid "Withholding Tax Rates" +msgstr "Ritenuta D'Acconto Validita" + +#: code:addons/l10n_it_withholding_tax/wizard/create_wt_statement.py:101 +#: model:ir.model,name:l10n_it_withholding_tax.model_withholding_tax_statement +#: view:withholding.tax.statement:l10n_it_withholding_tax.view_withholding_tax_statement_search #. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:119 #, python-format -msgid "Payable withholding - " -msgstr "Ritenute Pagabili - " +msgid "Withholding Tax Statement" +msgstr "Movimento Ritenuta" +#: model:ir.model,name:l10n_it_withholding_tax.model_withholding_tax_voucher_line #. module: l10n_it_withholding_tax -#: model:ir.model,name:l10n_it_withholding_tax.model_account_voucher -msgid "Accounting Voucher" -msgstr "Voucher contabile" +msgid "Withholding Tax Voucher Line" +msgstr "Ritenuta D'Acconto Linee voucher" +#: view:withholding.tax.statement:l10n_it_withholding_tax.view_withholding_statement_form +#: view:withholding.tax.statement:l10n_it_withholding_tax.view_withholding_statement_tree #. module: l10n_it_withholding_tax -#: field:account.invoice,withholding_amount:0 -msgid "Withholding amount" -msgstr "Totale Ritenute" +msgid "Withholding Tax statement" +msgstr "Situazione Ritenuta" +#: field:account.invoice,withholding_tax_amount:0 +#: field:account.invoice.withholding.tax,withholding_tax_id:0 +#: model:ir.ui.menu,name:l10n_it_withholding_tax.of_wt_main #. module: l10n_it_withholding_tax -#: model:ir.model,name:l10n_it_withholding_tax.model_account_invoice -msgid "Invoice" -msgstr "Fattura" +msgid "Withholding tax" +msgstr "Ritenuta" + +#: model:ir.actions.act_window,name:l10n_it_withholding_tax.action_withholding_tax +#. module: l10n_it_withholding_tax +msgid "Withhoulding Tax" +msgstr "Ritenuta" +#: model:ir.actions.act_window,name:l10n_it_withholding_tax.action_withholding_tax_move #. module: l10n_it_withholding_tax -#: field:res.company,withholding_journal_id:0 -msgid "Withholding journal" -msgstr "Sezionale Ritenute" +msgid "Withhoulding Tax Move" +msgstr "Voce Ritenuta" +#: model:ir.actions.act_window,name:l10n_it_withholding_tax.action_withholding_tax_statement +#. module: l10n_it_withholding_tax +msgid "Withhoulding Tax Statement" +msgstr "Situazione Ritenuta" + +#: code:addons/l10n_it_withholding_tax/wizard/create_wt_statement.py:40 #. module: l10n_it_withholding_tax -#: code:addons/l10n_it_withholding_tax/account.py:88 #, python-format -msgid "The company does not have an associated Withholding account" -msgstr "L'Azienda non ha un conto associato per le Ritenute" +msgid "You can choose Only ONE move." +msgstr "You can choose Only ONE move." + +#: view:account.voucher:l10n_it_withholding_tax.view_withholding_voucher_payment_supplier_form +#: view:account.voucher:l10n_it_withholding_tax.view_withholding_voucher_vendor_receipt_form +#. module: l10n_it_withholding_tax +msgid "onchange_amount(amount, amount_unreconciled, amount_residual_withholding_tax, context)" +msgstr "onchange_amount(amount, amount_unreconciled, amount_residual_withholding_tax, context)" +#: view:account.voucher:l10n_it_withholding_tax.view_withholding_voucher_payment_supplier_form +#: view:account.voucher:l10n_it_withholding_tax.view_withholding_voucher_vendor_receipt_form #. module: l10n_it_withholding_tax -#: field:account.voucher,withholding_move_ids:0 -msgid "Withholding Tax Entries" -msgstr "Voci Tasse Ritenute" +msgid "onchange_reconcile(reconcile, amount, amount_unreconciled, amount_residual_withholding_tax, context)" +msgstr "onchange_reconcile(reconcile, amount, amount_unreconciled, amount_residual_withholding_tax, context)" diff --git a/l10n_it_withholding_tax/models/__init__.py b/l10n_it_withholding_tax/models/__init__.py new file mode 100644 index 000000000000..c591b4bc6958 --- /dev/null +++ b/l10n_it_withholding_tax/models/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# Copyright © 2015 Alessandro Camilli () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from . import account +from . import voucher +from . import withholding_tax diff --git a/l10n_it_withholding_tax/models/account.py b/l10n_it_withholding_tax/models/account.py new file mode 100644 index 000000000000..4bfdb76f2987 --- /dev/null +++ b/l10n_it_withholding_tax/models/account.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# Copyright © 2015 Alessandro Camilli () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from openerp import models, fields, api +import openerp.addons.decimal_precision as dp + + +class account_move(models.Model): + _inherit = "account.move" + + @api.one + def _prepare_wt_values(self): + + partner = False + wt_competence = {} + + # Fist : Partner and WT competence + for line in self.line_id: + if line.partner_id: + partner = line.partner_id + if partner.property_account_position: + for wt in ( + partner.property_account_position.withholding_tax_ids + ): + wt_competence[wt.id] = { + 'withholding_tax_id': wt.id, + 'partner_id': partner.id, + 'date': self.date, + 'account_move_id': self.id, + 'wt_account_move_line_id': False, + 'base': 0, + 'amount': 0, + } + break + # After : Loking for WT lines + wt_amount = 0 + for line in self.line_id: + domain = [] + # WT line + if line.credit: + domain.append( + ('account_payable_id', '=', line.account_id.id) + ) + amount = line.credit + else: + domain.append( + ('account_receivable_id', '=', line.account_id.id) + ) + amount = line.debit + wt_ids = self.pool['withholding.tax'].search(self.env.cr, + self.env.uid, + domain) + if wt_ids: + wt_amount += amount + if ( + wt_competence and wt_competence[wt_ids[0]] and + 'amount' in wt_competence[wt_ids[0]] + ): + wt_competence[wt_ids[0]]['wt_account_move_line_id'] = ( + line.id) + wt_competence[wt_ids[0]]['amount'] = wt_amount + wt_competence[wt_ids[0]]['base'] = ( + self.pool['withholding.tax'].get_base_from_tax( + self.env.cr, self.env.uid, + wt_ids[0], wt_amount) + ) + + wt_codes = [] + if wt_competence: + for key, val in wt_competence.items(): + wt_codes.append(val) + res = { + 'partner_id': partner and partner.id or False, + 'move_id': self.id, + 'invoice_id': False, + 'date': self.date, + 'base': wt_codes and wt_codes[0]['base'] or 0, + 'tax': wt_codes and wt_codes[0]['amount'] or 0, + 'withholding_tax_id': ( + wt_codes and wt_codes[0]['withholding_tax_id'] or False), + 'wt_account_move_line_id': ( + wt_codes and wt_codes[0]['wt_account_move_line_id'] or False), + 'amount': wt_codes[0]['amount'], + } + + return res + + +class account_move_line(models.Model): + _inherit = "account.move.line" + + withholding_tax_amount = fields.Float(string='Withholding Tax Amount') + + +class account_fiscal_position(models.Model): + _inherit = "account.fiscal.position" + + withholding_tax_ids = fields.Many2many( + 'withholding.tax', 'account_fiscal_position_withholding_tax_rel', + 'fiscal_position_id', 'withholding_tax_id', string='Withholding Tax') + + +class account_invoice(models.Model): + _inherit = "account.invoice" + + @api.multi + @api.depends('withholding_tax_line') + def _amount_withholding_tax(self): + res = {} + dp_obj = self.env['decimal.precision'] + for invoice in self: + withholding_tax_amount = 0.0 + for wt_line in invoice.withholding_tax_line: + withholding_tax_amount += round( + wt_line.tax, dp_obj.precision_get('Account')) + invoice.amount_net_pay = invoice.amount_total - \ + withholding_tax_amount + invoice.withholding_tax_amount = withholding_tax_amount + return res + + withholding_tax = fields.Boolean('Withholding Tax') + withholding_tax_line = fields.One2many( + 'account.invoice.withholding.tax', 'invoice_id', 'Withholding Tax', + readonly=True, states={'draft': [('readonly', False)]}) + withholding_tax_amount = fields.Float( + compute='_amount_withholding_tax', + digits=dp.get_precision('Account'), string='Withholding tax', + store=True, readonly=True) + amount_net_pay = fields.Float( + compute='_amount_withholding_tax', + digits_compute=dp.get_precision('Account'), string='Net To Pay', + store=True, readonly=True) + + @api.multi + def action_move_create(self): + ''' + Split amount withholding tax on account move lines + ''' + dp_obj = self.env['decimal.precision'] + res = super(account_invoice, self).action_move_create() + + for inv in self: + # Rates + rate_num = 0 + for move_line in inv.move_id.line_id: + if not move_line.date_maturity: + continue + rate_num += 1 + # + if rate_num: + wt_rate = round(inv.withholding_tax_amount / rate_num, + dp_obj.precision_get('Account')) + wt_residual = inv.withholding_tax_amount + # Re-read move lines to assign the amounts of wt + i = 0 + for move_line in inv.move_id.line_id: + if not move_line.date_maturity: + continue + i += 1 + if i == rate_num: + wt_amount = wt_residual + else: + wt_amount = wt_rate + wt_residual -= wt_amount + # update line + move_line.write({'withholding_tax_amount': wt_amount}) + + # Align with WT statement + for wt_inv_line in inv.withholding_tax_line: + wt_inv_line._align_statement() + + return res + + @api.multi + def compute_all_withholding_tax(self): + + for invoice in self: + # Clear for recompute o because there isn't withholding_tax to True + if invoice.fiscal_position or not invoice.withholding_tax: + self.env.cr.execute( + "DELETE FROM " + "account_invoice_withholding_tax WHERE invoice_id=%s ", + (invoice.id,)) + if invoice.withholding_tax and invoice.fiscal_position and \ + invoice.fiscal_position.withholding_tax_ids: + for tax in invoice.fiscal_position.withholding_tax_ids: + tot_invoice = 0 + withholding_tax = tax.compute_amount(tot_invoice, + invoice.id) + val = { + 'invoice_id': invoice.id, + 'withholding_tax_id': tax.id, + 'base': withholding_tax['base'], + 'tax': withholding_tax['tax'] + } + self.env['account.invoice.withholding.tax'].create(val) + + @api.one + def button_reset_taxes(self): + res = super(account_invoice, self).button_reset_taxes() + self.compute_all_withholding_tax() + return res + + @api.onchange('fiscal_position') + def onchange_fiscal_position(self): + use_wt = False + if self.fiscal_position and self.fiscal_position.withholding_tax_ids: + use_wt = True + self.withholding_tax = use_wt + + +class account_invoice_line(models.Model): + _inherit = "account.invoice.line" + ''' + def compute_amount_line(self, cr, uid, line): + + dp_obj = self.pool['decimal.precision'] + price_subtotal = 0 + price = line['price_unit'] * (1-(line['discount'] or 0.0)/100.0) + if 'discount2' in line: # field of my customization + price = price * (1-(line['discount2'] or 0.0)/100.0) + price_subtotal = round(price * line['quantity'], + dp_obj.precision_get(cr, uid, 'Account')) + + return price_subtotal''' + + +class account_invoice_withholding_tax(models.Model): + ''' + Withholding tax lines in the invoice + ''' + + _name = 'account.invoice.withholding.tax' + _description = 'Invoice Withholding Tax Line' + + invoice_id = fields.Many2one('account.invoice', string='Invoice', + ondelete="cascade") + withholding_tax_id = fields.Many2one('withholding.tax', + string='Withholding tax') + base = fields.Float('Base') + tax = fields.Float('Tax') + + @api.multi + def _align_statement(self): + ''' + Align statement values with wt lines invoice + ''' + wt_st_id = False + for wt_inv_line in self: + domain = [ + ('move_id', '=', wt_inv_line.invoice_id.move_id.id), + ('withholding_tax_id', '=', wt_inv_line.withholding_tax_id.id), + ] + wt_st_ids = self.env['withholding.tax.statement'].search(domain) + # Create statemnt if doesn't exist + if not wt_st_ids: + vals = { + 'date': wt_inv_line.invoice_id.move_id.date, + 'move_id': wt_inv_line.invoice_id.move_id.id, + 'invoice_id': wt_inv_line.invoice_id.id, + 'partner_id': wt_inv_line.invoice_id.partner_id.id, + 'withholding_tax_id': wt_inv_line.withholding_tax_id.id, + } + wt_st_id = self.env['withholding.tax.statement'].create(vals) + else: + wt_st_id = wt_st_ids + # Update values + vals = { + 'base': wt_inv_line.base, + 'tax': wt_inv_line.tax + } + wt_st_id.write(vals) + + return wt_st_id + + @api.onchange('fiscal_position') + def onchange_fiscal_position(self): + use_wt = False + if self.fiscal_position and self.fiscal_position.withholding_tax_ids: + use_wt = True + self.withholding_tax = use_wt + + @api.onchange('withholding_tax_id') + def onchange_withholding_tax_id(self): + if self.withholding_tax_id: + tot_invoice = 0 + for inv_line in self.invoice_id.invoice_line: + tot_invoice += inv_line.price_subtotal + tax = self.withholding_tax_id.compute_amount( + tot_invoice, invoice_id=None) + self.base = tax['base'] + self.tax = tax['tax'] diff --git a/l10n_it_withholding_tax/models/voucher.py b/l10n_it_withholding_tax/models/voucher.py new file mode 100644 index 000000000000..ecd27db05acc --- /dev/null +++ b/l10n_it_withholding_tax/models/voucher.py @@ -0,0 +1,560 @@ +# -*- coding: utf-8 -*- +# Copyright © 2015 Alessandro Camilli () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp.osv import orm, fields +import openerp.addons.decimal_precision as dp + + +class account_voucher(orm.Model): + _inherit = "account.voucher" + + def recompute_voucher_lines(self, cr, uid, ids, partner_id, journal_id, + price, currency_id, ttype, date, context=None): + ''' + Compute original amount of WT of rate + ''' + move_line_obj = self.pool['account.move.line'] + voucher_line_obj = self.pool['account.voucher.line'] + dp_obj = self.pool['decimal.precision'] + res = super(account_voucher, self).recompute_voucher_lines( + cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, + date, context=context) + + def _compute_wt_values(lines): + amount_overflow_residual = 0.0 + # For each line, WT + for line in lines: + if 'move_line_id' in line and line['move_line_id']: + move_line = move_line_obj.browse(cr, uid, + line['move_line_id']) + line['amount_original_withholding_tax'] = \ + move_line.withholding_tax_amount + line['amount_residual_withholding_tax'] = \ + voucher_line_obj.\ + compute_amount_residual_withholdin_tax( + cr, uid, line, context=None) + # Recompute automatic values on amount: + # The amount_residual_currency on account_move_line, doesn't see + # the WT values + if lines and lines[0]['amount']: + # For each amount to redistribuite + tot_amount = 0 + for line in lines: + tot_amount += line['amount'] + \ + line['amount_residual_withholding_tax'] + + # Redistribuite amount + extra_amount = 0 + for line in lines: + if tot_amount <= 0: + break + save_amount = line['amount'] + line['amount'] += extra_amount + if ( + line['amount'] > + ( + line['amount_unreconciled'] - + line['amount_residual_withholding_tax'] + ) + ): + line['amount'] = line['amount_unreconciled'] \ + - line['amount_residual_withholding_tax'] + line['amount'] = round( + line['amount'], dp_obj.precision_get(cr, uid, + 'Account')) + extra_amount += (save_amount - line['amount']) + tot_amount -= line['amount'] + # Allocate WT + for line in lines: + if 'move_line_id' in line and line['move_line_id']: + move_line = move_line_obj.browse(cr, uid, + line['move_line_id']) + if line['amount'] or amount_overflow_residual: + # Assign overflow from other lines + if amount_overflow_residual: + if ( + (line['amount'] + amount_overflow_residual) <= + ( + line['amount_unreconciled'] - + line['amount_residual_withholding_tax'] + ) + ): + line['amount'] += amount_overflow_residual + amount_overflow_residual = 0.0 + else: + line['amount'] = line['amount_unreconciled'] \ + - line['amount_residual_withholding_tax'] + # Compute WT + line['amount_withholding_tax'] = \ + voucher_line_obj.compute_amount_withholdin_tax( + cr, uid, line['amount'], + line['amount_unreconciled'], + line['amount_residual_withholding_tax'], + context=None) + # WT can generate an overflow. It will bw assigned to + # next line + amount_overflow = line['amount'] \ + + line['amount_withholding_tax'] \ + - line['amount_unreconciled'] + if amount_overflow > 0: + line['amount'] -= amount_overflow + amount_overflow_residual += amount_overflow + line['amount_original'] -= \ + line['amount_original_withholding_tax'] + + return lines + if partner_id: + # resolve lists of commands into lists of dicts + line_dr_ids_ctrl = res['value']['line_dr_ids'] + line_dr_ids = [] + for l in line_dr_ids_ctrl: + if isinstance(l, dict): + line_dr_ids.append(l) + line_cr_ids_ctrl = res['value']['line_cr_ids'] + line_cr_ids = [] + for l in line_cr_ids_ctrl: + if isinstance(l, dict): + line_cr_ids.append(l) + + _compute_wt_values(line_dr_ids) + _compute_wt_values(line_cr_ids) + + return res + + def voucher_move_line_create( + self, cr, uid, voucher_id, line_total, move_id, company_currency, + current_currency, context=None): + ''' + Add WT line to registration and change amount on debit/credit line of + the invoice + ''' + move_line_obj = self.pool['account.move.line'] + voucher_line_obj = self.pool['account.voucher.line'] + payment_term_obj = self.pool['account.payment.term'] + reconcile_obj = self.pool['account.move.reconcile'] + line_total, rec_list_ids = super(account_voucher, self).\ + voucher_move_line_create(cr, uid, voucher_id, line_total, move_id, + company_currency, current_currency, + context=context) + + def _unreconcile_move_line(move_line): + ''' + Remove reconciliation to change amounts + ''' + recs = [] + recs_to_rereconcile = [] + if move_line.reconcile_id: + recs += [move_line.reconcile_id.id] + if move_line.reconcile_partial_id: + recs += [move_line.reconcile_partial_id.id] + # If there are other partial payments, I save the id line to + # future reconcile + cr.execute('SELECT id FROM account_move_line WHERE \ + reconcile_partial_id=%s AND id <> %s', + (move_line.reconcile_partial_id.id, move_line.id)) + for l in cr.dictfetchall(): + recs_to_rereconcile.append(l['id']) + reconcile_obj.unlink(cr, uid, recs) + return recs_to_rereconcile + + # rec_list_ids id payment move line with invoice move_line to reconcile + rec_list_new_moves = [] + for rec in rec_list_ids: + line_move_to_pay = move_line_obj.browse(cr, uid, rec[1]) + line_payment = move_line_obj.browse(cr, uid, rec[0]) + # Remove reconciliation to change amounts + lines_to_rereconcile = _unreconcile_move_line(line_move_to_pay) + for r_line_id in lines_to_rereconcile: + rec_list_new_moves.append([r_line_id, line_move_to_pay.id]) + _unreconcile_move_line(line_payment) + # line voucher with WT + domain = [('voucher_id', '=', voucher_id), ('move_line_id', '=', + line_move_to_pay.id)] + v_line_payment_ids = voucher_line_obj.search(cr, uid, domain) + for v_line in voucher_line_obj.browse(cr, uid, v_line_payment_ids): + voucher = v_line.voucher_id + for wt_v_line in v_line.withholding_tax_line_ids: + credit = 0.0 + debit = 0.0 + if v_line.move_line_id.debit: + debit = wt_v_line.amount + else: + credit = wt_v_line.amount + # account + if line_move_to_pay.account_id.type == 'receivable': + wt_account_id = wt_v_line.withholding_tax_id.\ + account_receivable_id.id + else: + wt_account_id = wt_v_line.withholding_tax_id\ + .account_payable_id.id + # Line WT + payment_lines = payment_term_obj.compute( + cr, uid, wt_v_line.withholding_tax_id.payment_term.id, + wt_v_line.amount, voucher.date or False, + context=context) + line_wt_ids = [] + for payment_line in payment_lines: + p_date_maturity = payment_line[0] + p_credit = 0.0 + p_debit = 0.0 + if debit: + p_debit = payment_line[1] + else: + p_credit = payment_line[1] + val_move_line = { + 'journal_id': voucher.journal_id.id, + 'period_id': voucher.period_id.id, + 'name': ( + wt_v_line.withholding_tax_id.name + ' ' + + voucher.partner_id.name or '/'), + 'account_id': wt_account_id, + 'move_id': move_id, + 'partner_id': False, + 'currency_id': ( + v_line.move_line_id.currency_id.id or + False), + 'analytic_account_id': ( + v_line.account_analytic_id and + v_line.account_analytic_id.id or False), + 'quantity': 1, + 'credit': p_credit, + 'debit': p_debit, + 'date': voucher.date, + 'date_maturity': p_date_maturity + } + line_wt_id = move_line_obj.create(cr, uid, + val_move_line) + line_wt_ids.append(line_wt_id) + + # Add amount WT to line debit/credit partner + val = { + 'credit': line_payment.credit + debit, + 'debit': line_payment.debit + credit + } + move_line_obj.write(cr, uid, [line_payment.id], val) + + # Merge with existing lines to reconcile + if rec_list_new_moves: + for rec_new in rec_list_new_moves: + for rec_ids in rec_list_ids: + if not rec_new[1] == rec_ids[1]: + continue + rec_ids.append(rec_new[0]) + + return (line_total, rec_list_ids) + + def action_move_line_create(self, cr, uid, ids, context=None): + ''' + Assign payment move to wt lines + ''' + res = super(account_voucher, self).action_move_line_create( + cr, uid, ids, context=None) + for voucher in self.browse(cr, uid, ids): + for v_line in voucher.line_ids: + for wt_v_line in v_line.withholding_tax_line_ids: + self.pool['withholding.tax.voucher.line']._align_wt_move( + cr, uid, [wt_v_line.id]) + return res + + +class account_voucher_line(orm.Model): + _inherit = "account.voucher.line" + + def _amount_withholding_tax(self, cr, uid, ids, name, args, context=None): + res = {} + for line in self.browse(cr, uid, ids, context=context): + res[line.id] = { + 'amount_original_withholding_tax': 0.0, + } + res[line.id]['amount_original_withholding_tax'] += \ + line.move_line_id.withholding_tax_amount + return res + + def _compute_balance(self, cr, uid, ids, name, args, context=None): + ''' + Extends the compute of original amounts for exclude from total the WT + amount + ''' + currency_pool = self.pool.get('res.currency') + rs_data = {} + for line in self.browse(cr, uid, ids, context=context): + ctx = context.copy() + ctx.update({'date': line.voucher_id.date}) + voucher_rate = self.pool.get('res.currency').read( + cr, uid, line.voucher_id.currency_id.id, ['rate'], + context=ctx)['rate'] + ctx.update({ + 'voucher_special_currency': + line.voucher_id.payment_rate_currency_id and + line.voucher_id.payment_rate_currency_id.id or False, + 'voucher_special_currency_rate': + line.voucher_id.payment_rate * voucher_rate}) + res = {} + company_currency = \ + line.voucher_id.journal_id.company_id.currency_id.id + voucher_currency = line.voucher_id.currency_id \ + and line.voucher_id.currency_id.id or company_currency + move_line = line.move_line_id or False + + if not move_line: + res['amount_original'] = 0.0 + res['amount_unreconciled'] = 0.0 + res['amount_withholding_tax'] = 0.0 + elif move_line.currency_id \ + and voucher_currency == move_line.currency_id.id: + # modify for WT + res['amount_original'] = abs( + move_line.amount_currency - + move_line.withholding_tax_amount) + res['amount_unreconciled'] = abs( + move_line.amount_residual_currency) + else: + # always use the amount booked in the company currency as the + # basis of the conversion into the voucher currency + res['amount_original'] = currency_pool.compute( + cr, uid, company_currency, voucher_currency, + move_line.credit or move_line.debit or 0.0, context=ctx) + res['amount_unreconciled'] = currency_pool.compute( + cr, uid, company_currency, voucher_currency, + abs(move_line.amount_residual), context=ctx) + # add for WT + res['amount_original'] -= move_line.withholding_tax_amount + + rs_data[line.id] = res + return rs_data + + _columns = { + 'amount_original': fields.function( + _compute_balance, multi='dc', type='float', + string='Original Amount', store=True, + digits_compute=dp.get_precision('Account')), + 'amount_original_withholding_tax': fields.function( + _amount_withholding_tax, + digits_compute=dp.get_precision('Account'), + string='Withholding Tax Original', multi='withholding_tax'), + 'amount_residual_withholding_tax': fields.float( + 'Withholding Tax Amount Residual'), + 'amount_withholding_tax': fields.float( + 'Withholding Tax Amount'), + 'withholding_tax_line_ids': fields.one2many( + 'withholding.tax.voucher.line', 'voucher_line_id', + 'Withholding Tax Lines'), + } + + def onchange_amount(self, cr, uid, ids, amount, amount_unreconciled, + amount_residual_withholding_tax, context=None): + res = super(account_voucher_line, self).onchange_amount( + cr, uid, ids, amount, amount_unreconciled, context=context) + dp_obj = self.pool['decimal.precision'] + wt_amount = self.compute_amount_withholdin_tax( + cr, uid, amount, amount_unreconciled, + amount_residual_withholding_tax, context) + res['value'].update({'amount_withholding_tax': wt_amount}) + + # Setting for Total amount + if (amount + wt_amount) >= round( + amount_unreconciled, dp_obj.precision_get(cr, uid, 'Account')): + res['value'].update({'reconcile': True}) + res['value'].update({'amount': amount}) + + return res + + def onchange_reconcile(self, cr, uid, ids, reconcile, amount, + amount_unreconciled, + amount_residual_withholding_tax, + context=None): + ''' + TO CONSIDER: Amount tot = amount net + amount WT + ''' + res = super(account_voucher_line, self).onchange_reconcile( + cr, uid, ids, reconcile, amount, amount_unreconciled, + context=context) + if reconcile: + amount = amount_unreconciled + wt_amount = self.compute_amount_withholdin_tax( + cr, uid, amount, amount_unreconciled, + amount_residual_withholding_tax, context) + res['value']['amount'] = amount - wt_amount + return res + + def compute_amount_residual_withholdin_tax( + self, cr, uid, line, context=None): + ''' + WT residual = WT amount original - (All WT amounts in voucher posted) + ''' + wt_amount_residual = 0.0 + if 'move_line_id' not in line or not line['move_line_id']: + return wt_amount_residual + domain = [('move_line_id', '=', line['move_line_id'])] + v_line_ids = self.search(cr, uid, domain) + wt_amount_residual = line['amount_original_withholding_tax'] + for v_line in self.browse(cr, uid, v_line_ids): + if v_line.voucher_id.state == 'posted': + wt_amount_residual -= v_line.amount_withholding_tax + + return wt_amount_residual + + def compute_amount_withholdin_tax( + self, cr, uid, amount, amount_unreconciled, wt_amount_residual, + context=None): + dp_obj = self.pool['decimal.precision'] + wt_amount = 0.0 + # Total amount + amount_tot = amount + wt_amount_residual + base_amount = amount_unreconciled - wt_amount_residual + if amount_tot >= round(amount_unreconciled, + dp_obj.precision_get(cr, uid, 'Account')): + wt_amount = wt_amount_residual + # Partial amount ( ratio with amount net) + else: + wt_amount = round( + wt_amount_residual * (1.0 * amount / base_amount), + dp_obj.precision_get(cr, uid, 'Account')) + return wt_amount + + def recompute_withholding_tax_voucher_line( + self, cr, uid, voucher_line_id, context=None): + ''' + Split amount voucher line second WT lines invoice + ''' + res = [] + invoice_obj = self.pool['account.invoice'] + wt_voucher_line_obj = self.pool['withholding.tax.voucher.line'] + dp_obj = self.pool['decimal.precision'] + + voucher_line = self.browse(cr, uid, voucher_line_id) + # delete existing wt lines + domain = [('voucher_line_id', '=', voucher_line_id)] + wtv_line_ids = wt_voucher_line_obj.search(cr, uid, domain) + wt_voucher_line_obj.unlink(cr, uid, wtv_line_ids) + # + if voucher_line.amount_withholding_tax: + domain = [('move_id', '=', voucher_line.move_line_id.move_id.id)] + inv_ids = invoice_obj.search(cr, uid, domain) + for inv in invoice_obj.browse(cr, uid, inv_ids): + if len(inv.withholding_tax_line): + rate_num = len(inv.withholding_tax_line) + # Rates + wt_amount_rate = round( + voucher_line.amount_withholding_tax / rate_num, + dp_obj.precision_get(cr, uid, 'Account')) + wt_residual = voucher_line.amount_withholding_tax + # Re-read move lines to assign the amounts of wt + i = 0 + for wt_invoice_line in inv.withholding_tax_line: + i += 1 + if i == rate_num: + wt_amount = wt_residual + else: + wt_amount = wt_amount_rate + wt_residual -= wt_amount + + val = { + 'voucher_line_id': voucher_line_id, + 'withholding_tax_id': + wt_invoice_line.withholding_tax_id.id, + 'amount': wt_amount + } + wt_voucher_line_obj.create(cr, uid, val) + + return res + + def create(self, cr, uid, vals, *args, **kwargs): + res_id = super(account_voucher_line, self).create( + cr, uid, vals, *args, **kwargs) + self.recompute_withholding_tax_voucher_line( + cr, uid, res_id, context=None) + return res_id + + def write(self, cr, uid, ids, vals, context=None): + res = super(account_voucher_line, self).write( + cr, uid, ids, vals, context) + if 'amount_withholding_tax' in vals: + for line_id in ids: + self.recompute_withholding_tax_voucher_line(cr, uid, line_id) + return res + + +class withholding_tax_voucher_line(orm.Model): + _name = 'withholding.tax.voucher.line' + _description = 'Withholding Tax Voucher Line' + + _columns = { + 'voucher_line_id': fields.many2one( + 'account.voucher.line', 'Account Voucher Line', + ondelete='cascade'), + 'withholding_tax_id': fields.many2one( + 'withholding.tax', 'Withholding Tax'), + 'amount': fields.float('Amount'), + } + + def _align_wt_move(self, cr, uid, ids, context=None): + ''' + Align with wt move lines + ''' + wt_statement_obj = self.pool['withholding.tax.statement'] + wt_move_obj = self.pool['withholding.tax.move'] + payment_term_obj = self.pool['account.payment.term'] + for wt_v_line in self.browse(cr, uid, ids): + # Search statemnt of competence + domain = [('move_id', '=', + wt_v_line.voucher_line_id.move_line_id.move_id.id), + ('withholding_tax_id', '=', + wt_v_line.withholding_tax_id.id)] + wt_st_ids = wt_statement_obj.search(cr, uid, domain) + if wt_st_ids: + wt_st_id = wt_st_ids[0] + else: + wt_st_id = False + # Date maturity + # TODO : split wt moves for payment with more lines + payment_lines = payment_term_obj.compute( + cr, uid, wt_v_line.withholding_tax_id.payment_term.id, + wt_v_line.amount, + wt_v_line.voucher_line_id.voucher_id.date or False, + context=context) + if payment_lines: + p_date_maturity = payment_lines[0][0] + # Create move if doesn't exist + domain = [('wt_voucher_line_id', '=', wt_v_line.id), + ('move_line_id', '=', False)] + wt_move_ids = wt_move_obj.search(cr, uid, domain) + wt_move_vals = { + 'statement_id': wt_st_id, + 'date': wt_v_line.voucher_line_id.voucher_id.date, + 'partner_id': + wt_v_line.voucher_line_id.voucher_id.partner_id.id, + 'wt_voucher_line_id': wt_v_line.id, + 'withholding_tax_id': wt_v_line.withholding_tax_id.id, + 'account_move_id': + wt_v_line.voucher_line_id.voucher_id.move_id.id, + 'date_maturity': + p_date_maturity or + wt_v_line.voucher_line_id.move_line_id.date_maturity + } + if not wt_move_ids: + wt_move_id = wt_move_obj.create(cr, uid, wt_move_vals) + else: + wt_move_id = wt_move_ids[0] + + # Update values + wt_move_vals.update({'amount': wt_v_line.amount}) + wt_move_obj.write(cr, uid, [wt_move_id], wt_move_vals) + # wt_move.write(wt_move_vals) + + return True + + def create(self, cr, uid, vals, *args, **kwargs): + res_id = super(withholding_tax_voucher_line, self).create( + cr, uid, vals, *args, **kwargs) + # Align with wt move + self._align_wt_move(cr, uid, [res_id]) + return res_id + + def write(self, cr, uid, ids, vals, context=None): + res = super(withholding_tax_voucher_line, self).write( + cr, uid, ids, vals, context) + # Align with wt move + self._align_wt_move(cr, uid, ids) + return res diff --git a/l10n_it_withholding_tax/models/withholding_tax.py b/l10n_it_withholding_tax/models/withholding_tax.py new file mode 100644 index 000000000000..e3d5b773381c --- /dev/null +++ b/l10n_it_withholding_tax/models/withholding_tax.py @@ -0,0 +1,234 @@ +# -*- coding: utf-8 -*- +# Copyright © 2015 Alessandro Camilli () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from openerp import models, fields, api, _ +from openerp.exceptions import ValidationError +from openerp import netsvc + + +class withholding_tax(models.Model): + _name = 'withholding.tax' + _description = 'Withholding Tax' + + @api.one + @api.depends('rate_ids.date_start', 'rate_ids.date_stop', 'rate_ids.base', + 'rate_ids.tax') + def _get_rate(self): + self.env.cr.execute(''' + SELECT tax, base FROM withholding_tax_rate + WHERE withholding_tax_id = %s + and (date_start <= current_date or date_start is null) + ORDER by date_start LIMIT 1''', + (self.id,)) + rate = self.env.cr.fetchone() + if rate: + self.tax = rate[0] + self.base = rate[1] + else: + self.tax = 0 + self.base = 1 + + active = fields.Boolean('Active', default=True) + name = fields.Char('Name', size=256, required=True) + certification = fields.Boolean('Certification') + comment = fields.Text('Text') + account_receivable_id = fields.Many2one( + 'account.account', + 'Account Receivable', required=True, + domain=[('type', '=', 'receivable')]) + account_payable_id = fields.Many2one( + 'account.account', + 'Account Payable', required=True, domain=[('type', '=', 'payable')]) + payment_term = fields.Many2one('account.payment.term', 'Payment Terms', + required=True) + tax = fields.Float(string='Tax %', compute='_get_rate') + base = fields.Float(string='Base', compute='_get_rate') + rate_ids = fields.One2many('withholding.tax.rate', 'withholding_tax_id', + 'Rates', required=True) + + def compute_amount(self, amount_invoice, invoice_id=None): + invoice_obj = self.env['account.invoice'] + res = { + 'base': 0, + 'tax': 0 + } + if not amount_invoice and invoice_id: + invoice = invoice_obj.browse(invoice_id) + amount_invoice = invoice.amount_untaxed + # v7->v8 removed tax = self.browse(cr, uid, withholding_tax_id) + base = amount_invoice * self.base + tax = base * ((self.tax or 0.0) / 100.0) + + res['base'] = base + res['tax'] = tax + + return res + + @api.one + def get_base_from_tax(self, wt_amount): + ''' + 100 * wt_amount 1 + --------------- * ------- + % tax Coeff + ''' + dp_obj = self.env['decimal.precision'] + base = 0 + if wt_amount: + # wt = self.browse(cr, uid, withholding_tax_id) + base = round((100 * wt_amount / self.tax) * (1 / self.base), + dp_obj.precision_get('Account')) + return base + + +class withholding_tax_rate(models.Model): + _name = 'withholding.tax.rate' + _description = 'Withholding Tax Rates' + + @api.one + @api.constrains('date_start', 'date_stop') + def _check_date(self): + if self.withholding_tax_id.active: + where = [] + if self.date_start: + where.append("((date_stop>='%s') or (date_stop is null))" % + (self.date_start,)) + if self.date_stop: + where.append("((date_start<='%s') or (date_start is null))" % + (self.date_stop,)) + + self.env.cr.execute( + 'SELECT id ' + 'FROM withholding_tax_rate ' + 'WHERE ' + ' and '.join(where) + (where and ' and ' or '') + + 'withholding_tax_id = %s ' + 'AND id <> %s', ( + self.withholding_tax_id.id, + self.id)) + if self.env.cr.fetchall(): + raise ValidationError( + _('Error! You cannot have 2 pricelist versions that \ + overlap!')) + + withholding_tax_id = fields.Many2one('withholding.tax', + string='Withholding Tax', + ondelete='cascade', readonly=True) + date_start = fields.Date(string='Date Start') + date_stop = fields.Date(string='Date Stop') + comment = fields.Text(string='Text') + base = fields.Float(string='Base Coeff.', default=1) + tax = fields.Float(string='Tax %') + + +class withholding_tax_statement(models.Model): + + ''' + The Withholding tax statement are created at the invoice validation + ''' + + _name = 'withholding.tax.statement' + _description = 'Withholding Tax Statement' + + @api.multi + @api.depends('move_ids.amount', 'move_ids.state') + def _compute_total(self): + for statement in self: + tot_wt_amount = 0 + tot_wt_amount_paid = 0 + for wt_move in statement.move_ids: + tot_wt_amount += wt_move.amount + if wt_move.state == 'paid': + tot_wt_amount_paid += wt_move.amount + statement.amount = tot_wt_amount + statement.amount_paid = tot_wt_amount_paid + + date = fields.Date('Date') + move_id = fields.Many2one('account.move', 'Account move', + ondelete='cascade') + invoice_id = fields.Many2one('account.invoice', 'Invoice', + ondelete='cascade') + partner_id = fields.Many2one('res.partner', 'Partner') + withholding_tax_id = fields.Many2one('withholding.tax', + string='Withholding Tax') + base = fields.Float('Base') + tax = fields.Float('Tax') + amount = fields.Float(string='WT amount', store=True, readonly=True, + compute='_compute_total') + amount_paid = fields.Float(string='WT amount paid', store=True, + readonly=True, compute='_compute_total') + move_ids = fields.One2many('withholding.tax.move', + 'statement_id', 'Moves') + + +class withholding_tax_move(models.Model): + + ''' + The Withholding tax moves are created at the payment of invoice using + voucher + ''' + _name = 'withholding.tax.move' + _description = 'Withholding Tax Move' + + state = fields.Selection([ + ('due', 'Due'), + ('paid', 'Paid'), + ], 'Status', readonly=True, copy=False, select=True, + default='due') + statement_id = fields.Many2one('withholding.tax.statement', 'Statement') + date = fields.Date('Date Competence') + wt_voucher_line_id = fields.Many2one('withholding.tax.voucher.line', + 'WT Account Voucher Line', + ondelete='cascade') + move_line_id = fields.Many2one( + 'account.move.line', 'Account Move line', + ondelete='cascade', help="Used from trace WT from other parts(BS)") + withholding_tax_id = fields.Many2one('withholding.tax', 'Withholding Tax') + amount = fields.Float('Amount') + partner_id = fields.Many2one('res.partner', 'Partner') + date_maturity = fields.Date('Date Maturity') + account_move_id = fields.Many2one('account.move', 'Account Move', + ondelete='cascade') + + @api.multi + def action_paid(self): + for pt in self: + wf_service = netsvc.LocalService("workflow") + wf_service.trg_validate(self.env.uid, self._name, pt.id, 'paid', + self.env.cr) + return True + + @api.multi + def action_set_to_draft(self): + for pt in self: + wf_service = netsvc.LocalService("workflow") + wf_service.trg_validate(self.env.uid, self._name, pt.id, 'cancel', + self.env.cr) + return True + + @api.multi + # def move_paid(self, cr, uid, ids, *args): + def move_paid(self): + for move in self: + if move.state in ['due']: + move.write({'state': 'paid'}) + return True + + @api.multi + # def move_set_due(self, cr, uid, ids, *args): + def move_set_due(self): + for move in self: + if move.state in ['paid']: + move.write({'state': 'due'}) + return True + + @api.multi + def unlink(self): + # To avoid if move is linked to voucher + for move in self: + if move.wt_voucher_line_id \ + and move.wt_voucher_line_id.voucher_line_id: + raise ValidationError( + _('Warning! You cannot delet move linked to voucher.You \ + must before delete the voucher.')) + return super(withholding_tax_move, self).unlink() diff --git a/l10n_it_withholding_tax/security/ir.model.access.csv b/l10n_it_withholding_tax/security/ir.model.access.csv new file mode 100644 index 000000000000..b1e8173840c1 --- /dev/null +++ b/l10n_it_withholding_tax/security/ir.model.access.csv @@ -0,0 +1,14 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" + +withholding_tax_manager,withholding_tax manager,model_withholding_tax,account.group_account_user,1,0,0,0 +withholding_tax_manager,withholding_tax manager,model_withholding_tax,account.group_account_manager,1,1,1,1 +withholding_tax_rate_manager,withholding_tax_rate manager,model_withholding_tax_rate,account.group_account_user,1,0,0,0 +withholding_tax_rate_manager,withholding_tax_rate manager,model_withholding_tax_rate,account.group_account_manager,1,1,1,1 +withholding_tax_voucher_line_manager,withholding_tax_voucher_line manager,model_withholding_tax_voucher_line,account.group_account_user,1,0,0,0 +withholding_tax_voucher_line_manager,withholding_tax_voucher_line manager,model_withholding_tax_voucher_line,account.group_account_manager,1,1,1,1 +withholding_tax_statement_user,withholding_tax_statement user,model_withholding_tax_statement,account.group_account_user,1,0,0,0 +withholding_tax_statement_manager,withholding_tax_statement manager,model_withholding_tax_statement,account.group_account_manager,1,1,1,1 +withholding_tax_move_user,withholding_tax_move user,model_withholding_tax_move,account.group_account_user,1,0,0,0 +withholding_tax_move_manager,withholding_tax_move manager,model_withholding_tax_move,account.group_account_manager,1,1,1,1 +account_invoice_withholding_tax_manager,account_invoice_withholding_tax manager,model_account_invoice_withholding_tax,account.group_account_user,1,0,0,0 +account_invoice_withholding_tax_manager,account_invoice_withholding_tax manager,model_account_invoice_withholding_tax,account.group_account_manager,1,1,1,1 diff --git a/l10n_it_withholding_tax/test/purchase_payment.yml b/l10n_it_withholding_tax/test/purchase_payment.yml deleted file mode 100644 index 910a69acad19..000000000000 --- a/l10n_it_withholding_tax/test/purchase_payment.yml +++ /dev/null @@ -1,105 +0,0 @@ -- - I configure the main company -- - !record {model: res.company, id: base.main_company}: - withholding_payment_term_id: account.account_payment_term - withholding_account_id: a_witholding - withholding_journal_id: account.miscellaneous_journal - authority_partner_id: tax_authority -- - In order to test account invoice I create a new supplier invoice -- - I create a Tax Codes -- - !record {model: account.tax.code, id: tax_case}: - name: Tax_case - company_id: base.main_company - sign: 1 -- - I create a Tax -- - !record {model: account.tax, id: tax10}: - name: Tax 10.0 - amount: 10.0 - type: fixed - sequence: 1 - company_id: base.main_company - type_tax_use: all - tax_code_id: tax_case -- - I set the context -- - !context - 'type': 'in_invoice' -- - I create a supplier invoice -- - !record {model: account.invoice, id: account_invoice_supplier_0, view: invoice_supplier_form}: - account_id: account.a_pay - company_id: base.main_company - currency_id: base.EUR - invoice_line: - - account_id: account.a_expense - name: 'Lawyer service' - price_unit: 100.0 - quantity: 1.0 - invoice_line_tax_id: - - tax10 - journal_id: account.expenses_journal - partner_id: base.res_partner_12 - has_withholding: True - withholding_amount: 20.0 -- - I check that Initially supplier invoice state is "Draft" -- - !assert {model: account.invoice, id: account_invoice_supplier_0}: - - state == 'draft' -- - I change the state of invoice to open by clicking Validate button -- - !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_supplier_0} -- - I check that the invoice state is now "Open" and 'Net Pay' is 90 -- - !assert {model: account.invoice, id: account_invoice_supplier_0}: - - state == 'open' - - net_pay == 90.0 -- - I create the voucher of payment with 90 -- - !record {model: account.voucher, id: account_voucher_0, view: account_voucher.view_vendor_payment_form}: - account_id: account.cash - amount: 90.0 - company_id: base.main_company - journal_id: account.bank_journal - name: 'Payment: invoice 0' - partner_id: base.res_partner_12 - period_id: account.period_3 - date: !eval time.strftime("%Y-03-10") - type: 'payment' -- - I check voucher state is draft -- - !assert {model: account.voucher, id: account_voucher_0}: - - state == 'draft' -- - I confirm the voucher -- - !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_0} -- - I check the entries -- - !python {model: account.voucher}: | - import time - voucher = self.browse(cr, uid, ref('account_voucher_0')) - assert (voucher.state=='posted'), "Voucher is not in posted state: %s" % voucher.state - assert (len(voucher.withholding_move_ids) == 1), "Withholding entry must be one, not %s" % len(voucher.withholding_move_ids) - for move_line in voucher.withholding_move_ids[0].line_id: - if move_line.account_id.id == ref('a_witholding'): - assert (move_line.credit==20.0), "withholding move line credit must be 20 instead of %s" % move_line.credit - assert (move_line.date_maturity==time.strftime("%Y-04-30")), "due date must be %s instead of %s" % (time.strftime("%Y-04-30"),move_line.date_maturity) -- - Finally i will Confirm the state of the invoice is paid -- - !assert {model: account.invoice, id: account_invoice_supplier_0}: - - state == 'paid' diff --git a/l10n_it_withholding_tax/views/account.xml b/l10n_it_withholding_tax/views/account.xml new file mode 100644 index 000000000000..4016ac6170f8 --- /dev/null +++ b/l10n_it_withholding_tax/views/account.xml @@ -0,0 +1,118 @@ + + + + + + + view.withholding.invoice.form + account.invoice + + + + + + + + +
+ + + + + + +
+ + + + + +
+
+
+
+ + + + + + +
+
+ + + + view.withholding.invoice.supplier.form + account.invoice + + + + + + + + + + + + + + +
+ + + + + +
+ +
+
+ + + + + + +
+
+ + + + view.withholding.tax.fiscal.position.form + account.fiscal.position + + + + + + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/l10n_it_withholding_tax/views/voucher.xml b/l10n_it_withholding_tax/views/voucher.xml new file mode 100644 index 000000000000..2e32e0623fc7 --- /dev/null +++ b/l10n_it_withholding_tax/views/voucher.xml @@ -0,0 +1,94 @@ + + + + + + + view.withholding.voucher.vendor.receipt.form + account.voucher + + + + + + + + + + onchange_amount(amount, amount_unreconciled, amount_residual_withholding_tax, context) + + + + onchange_reconcile(reconcile, amount, amount_unreconciled, amount_residual_withholding_tax, context) + + + + + + + + + + + + onchange_amount(amount, amount_unreconciled, amount_residual_withholding_tax, context) + + + + onchange_reconcile(reconcile, amount, amount_unreconciled, amount_residual_withholding_tax, context) + + + + + + + + + + + + view.withholding.voucher.payment.supplier.form + account.voucher + + + + + + + + + + onchange_amount(amount, amount_unreconciled, amount_residual_withholding_tax, context) + + + + onchange_reconcile(reconcile, amount, amount_unreconciled, amount_residual_withholding_tax, context) + + + + + + + + + + + + onchange_amount(amount, amount_unreconciled, amount_residual_withholding_tax, context) + + + onchange_reconcile(reconcile, amount, amount_unreconciled, amount_residual_withholding_tax, context) + + + + + + + + + + \ No newline at end of file diff --git a/l10n_it_withholding_tax/views/withholding_tax.xml b/l10n_it_withholding_tax/views/withholding_tax.xml new file mode 100644 index 000000000000..a7a5245398ed --- /dev/null +++ b/l10n_it_withholding_tax/views/withholding_tax.xml @@ -0,0 +1,242 @@ + + + + + + + + + view.withholding.tax.tree + withholding.tax + + + + + + + + + + + + + + view.withholding.tax.form + withholding.tax + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + Withhoulding Tax + withholding.tax + + + + + + + + + view.withholding.tax.statement.tree + withholding.tax.statement + + + + + + + + + + + + + + + + + view.withholding.tax.statement.form + withholding.tax.statement + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + view.withholding.tax.statement.search + withholding.tax.statement + + + + + + + + + + + + + + + Withhoulding Tax Statement + withholding.tax.statement + + + + + + + + + view.withholding.tax.move.tree + withholding.tax.move + + + + + + + + + + + + + + + view.withholding.tax.move.form + withholding.tax.move + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+
+ + + view.withholding.tax.move.search + withholding.tax.move + + + + + + + + + + + + + + + + + + Withhoulding Tax Move + withholding.tax.move + + + + + + +
+
\ No newline at end of file diff --git a/l10n_it_withholding_tax/wizard/__init__.py b/l10n_it_withholding_tax/wizard/__init__.py new file mode 100644 index 000000000000..5fdedd4ced90 --- /dev/null +++ b/l10n_it_withholding_tax/wizard/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# Copyright © 2015 Alessandro Camilli () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from . import create_wt_statement diff --git a/l10n_it_withholding_tax/wizard/create_wt_statement.py b/l10n_it_withholding_tax/wizard/create_wt_statement.py new file mode 100644 index 000000000000..61cbcfccb1c4 --- /dev/null +++ b/l10n_it_withholding_tax/wizard/create_wt_statement.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +# Copyright © 2015 Alessandro Camilli () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from openerp.osv import fields, orm +from openerp.tools.translate import _ + + +class wizard_create_wt_statement(orm.TransientModel): + + def default_get(self, cr, uid, fields, context=None): + + move_obj = self.pool['account.move'] + res = super(wizard_create_wt_statement, self).default_get( + cr, uid, fields, context=context) + + # Account moves selected + active_ids = context and context.get('active_ids', []) + if len(active_ids) > 1: + raise orm.except_orm(_('Warning!'), + _('You can choose Only ONE move.')) + # Controllo se esiste già il movimento + domain = [('move_id', '=', active_ids[0])] + st_ids = self.pool['withholding.tax.statement'].search(cr, uid, domain) + if st_ids: + raise orm.except_orm(_('Warning!'), + _('This Move is already present in the WT')) + data = move_obj._prepare_wt_values(cr, uid, active_ids) + res = data + return res + + _name = "withholding.tax.wizard.create.statement" + + _columns = { + + 'move_id': fields.many2one('account.move', 'Account Move', + readonly=True), + 'partner_id': fields.many2one('res.partner', 'Partner', + required=True), + 'date': fields.date('Date', required=True), + 'base': fields.float('Base'), + 'tax': fields.float('Tax'), + 'withholding_tax_id': fields.many2one( + 'withholding.tax', 'Withholding Tax', required=True), + 'wt_account_move_line_id': fields.many2one( + 'account.move.line', 'Account Move line', required=True), + 'amount': fields.float('WT amount') + + } + + def create_wt_statement(self, cr, uid, ids, context=None): + + for wiz in self.browse(cr, uid, ids): + # Statement + val = { + 'move_id': wiz.move_id.id, + 'date': wiz.date, + 'partner_id': wiz.partner_id.id, + 'withholding_tax_id': wiz.withholding_tax_id.id, + 'base': wiz.base, + 'tax': wiz.tax, + } + statement_id = self.pool['withholding.tax.statement'].create( + cr, uid, val) + # Moves + val = { + 'statement_id': statement_id, + 'account_move_id': wiz.move_id.id, + 'date': wiz.date, + 'partner_id': wiz.partner_id.id, + 'move_line_id': wiz.wt_account_move_line_id.id, + 'withholding_tax_id': wiz.withholding_tax_id.id, + 'amount': wiz.amount, + } + self.pool['withholding.tax.move'].create( + cr, uid, val) + + view_ref = self.pool.get('ir.model.data').get_object_reference( + cr, uid, 'openforce_withholding_tax', + 'of_withholding_statement_view_form') + return { + 'name': _('Withholding Tax Statement'), + 'view_type': 'form', + 'view_mode': 'form', + 'view_id': view_ref[1] or False, + 'res_model': 'withholding.tax.statement', + 'res_id': statement_id or False, + 'type': 'ir.actions.act_window', + 'nodestroy': True, + 'target': 'current', + 'domain': '[]', + } diff --git a/l10n_it_withholding_tax/wizard/create_wt_statement_view.xml b/l10n_it_withholding_tax/wizard/create_wt_statement_view.xml new file mode 100644 index 000000000000..511e376ac5ef --- /dev/null +++ b/l10n_it_withholding_tax/wizard/create_wt_statement_view.xml @@ -0,0 +1,61 @@ + + + + + + Create Withholding Tax Statement + withholding.tax.wizard.create.statement + +
+ + + + + + + + + + + + + + + + + + + + + + + + +