From 9defdc1f44882b9f0b25187042f9aacadf3e3393 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Fri, 12 Oct 2018 13:38:08 +0200 Subject: [PATCH 01/11] [WIP] refactoring --- account_export_ebp/__openerp__.py | 2 - account_export_ebp/models/__init__.py | 7 +- account_export_ebp/models/account_account.py | 78 +++++----- .../models/account_fiscalyear.py | 22 --- account_export_ebp/models/account_move.py | 82 ++++------- account_export_ebp/models/account_tax_code.py | 61 ++------ account_export_ebp/models/ebp_export.py | 2 +- account_export_ebp/models/res_company.py | 45 ++---- account_export_ebp/models/res_partner.py | 137 ++++++++++-------- .../views/view_account_account.xml | 2 +- .../views/view_account_export_ebp.xml | 1 - .../views/view_account_fiscalyear.xml | 19 --- .../views/view_account_move.xml | 6 +- .../views/view_account_tax_code.xml | 12 +- account_export_ebp/views/view_res_company.xml | 24 --- account_export_ebp/views/view_res_partner.xml | 10 +- .../wizard/wizard_add_suffix.py | 12 +- account_export_ebp/wizard/wizard_ebp.py | 85 ++--------- account_export_ebp/wizard/wizard_unexport.py | 2 +- 19 files changed, 212 insertions(+), 397 deletions(-) delete mode 100644 account_export_ebp/models/account_fiscalyear.py delete mode 100644 account_export_ebp/views/view_account_fiscalyear.xml delete mode 100644 account_export_ebp/views/view_res_company.xml diff --git a/account_export_ebp/__openerp__.py b/account_export_ebp/__openerp__.py index 0e6f517..f83e2e0 100644 --- a/account_export_ebp/__openerp__.py +++ b/account_export_ebp/__openerp__.py @@ -53,12 +53,10 @@ 'views/view_account_add_suffix.xml', 'views/view_account_export_ebp.xml', 'views/view_account_unexport_ebp.xml', - 'views/view_account_fiscalyear.xml', 'views/view_account_journal.xml', 'views/view_account_move.xml', 'views/view_account_tax_code.xml', 'views/view_ebp_export.xml', - 'views/view_res_company.xml', 'views/view_res_partner.xml', ], } diff --git a/account_export_ebp/models/__init__.py b/account_export_ebp/models/__init__.py index 3ecde81..ef1652e 100644 --- a/account_export_ebp/models/__init__.py +++ b/account_export_ebp/models/__init__.py @@ -1,10 +1,9 @@ # coding: utf-8 -from . import res_partner -from . import res_company from . import account_account from . import account_journal from . import account_move -from . import account_fiscalyear -from . import ebp_export from . import account_tax_code +from . import ebp_export +from . import res_company +from . import res_partner diff --git a/account_export_ebp/models/account_account.py b/account_export_ebp/models/account_account.py index 297b6e0..aa048fe 100644 --- a/account_export_ebp/models/account_account.py +++ b/account_export_ebp/models/account_account.py @@ -5,58 +5,54 @@ # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp.osv import fields -from openerp.osv.orm import Model +from openerp import _, api, fields, models +from openerp.exceptions import Warning as UserError -class account_account(Model): + +class AccountAccount(models.Model): _inherit = 'account.account' # Columns section - _columns = { - 'code': fields.char('Code', size=10, required=True, select=1), - 'export_tax_code': fields.boolean( - 'Export according to Tax Codes', - help="""If checked, when you export moves from this account,""" - """ it will create one account for each Tax Code"""), - 'ebp_code_no_tax': fields.char( - 'Tax Code\'s Account suffix in EBP (if no tax)', size=4, - help="When exporting Entries to EBP, this suffix will be" - " appended to the Account Number to make it a new Account," - " if Export according to tax Codes is checked, and" - " if no taxes is defined on the account move line."), - } + ebp_export_tax_code = fields.Boolean( + oldname='export_tax_code', + string='Export to EBP according to Tax Codes', + help="If checked, when you export moves from this account," + " it will create one account for each Tax Code") - # Defaults section - _defaults = { - 'export_tax_code': False, - } + ebp_code_no_tax = fields.Char( + string='Tax Code Suffix in EBP (if no tax)', + help="When exporting Entries to EBP, this suffix will be" + " appended to the Account Number to make it a new Account," + " if 'Export to EBP according to Tax Codes' is checked, and" + " if no taxes is defined on the account move line.") # Constraints section - def _check_code_length(self, cr, uid, ids, context=None): - for account in self.browse(cr, uid, ids, context=context): + @api.constrains( + 'code', 'type', 'company_id.fiscal_type', + 'is_intercompany_trade_fiscal_company') + def _constrains_code_length(self): + for account in self: if account.company_id.fiscal_type == 'fiscal_mother': if account.is_intercompany_trade_fiscal_company and\ len(account.code) > 6: - return False + raise UserError(_( + "The account code for a partner account cannot" + " exceed 6 characters for Fiscal Mother Company" + " (Intercompany Trade) so as to permit the EBP" + " export")) elif not account.is_intercompany_trade_fiscal_company and\ account.type in ('receivable', 'payable') and\ len(account.code) > 3: - return False - elif account.company_id.fiscal_type == 'normal': - if account.type in ('receivable', 'payable') and\ - len(account.code) > 6: - return False - return True - - _constraints = [ - ( - _check_code_length, - "The account code for a partner account cannot exceed\n" - " * 3 characters for Fiscal Mother Company (Regular Case);\n" - " * 6 characters for Fiscal Mother Company (Intercompany Trade);\n" - " * 6 characters for Normal Company ; \n" - " so as to permit the EBP export", - ['code', 'type', 'company_id', - 'is_intercompany_trade_fiscal_company']), - ] + raise UserError(_( + "The account code for a partner account cannot" + " exceed 3 characters for Fiscal Mother Company" + " (Regular Case) so as to permit the EBP" + " export")) + elif account.company_id.fiscal_type == 'normal': + if account.type in ('receivable', 'payable') and\ + len(account.code) > 6: + raise UserError(_( + "The account code for a partner account cannot" + " exceed 6 characters for Normal Company" + " so as to permit the EBP export")) diff --git a/account_export_ebp/models/account_fiscalyear.py b/account_export_ebp/models/account_fiscalyear.py deleted file mode 100644 index cf04a04..0000000 --- a/account_export_ebp/models/account_fiscalyear.py +++ /dev/null @@ -1,22 +0,0 @@ -# coding: utf-8 -# Copyright (C) 2010 - 2015: Numérigraphe SARL -# Copyright (C) 2015 - Today: GRAP (http://www.grap.coop) -# @author: Julien WESTE -# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from openerp import fields, models - - -class AccountFiscalyear(models.Model): - _inherit = "account.fiscalyear" - - # TODO Set default, by computing the last number + 1 - ebp_nb = fields.Integer( - string='EBP Fiscal Year Number', default=0, - help="This value should reflect the number of the fiscal year" - " as used by the EBP accounting software. This should be set" - " to the number of fiscal years recorded in EBP accounting" - " before this one - So for the first year the number is 0," - " for the second year the number is 1 and so on. This is used" - " for exporting accounting moves to EBP.") diff --git a/account_export_ebp/models/account_move.py b/account_export_ebp/models/account_move.py index 3f5c8d6..8e45b2f 100644 --- a/account_export_ebp/models/account_move.py +++ b/account_export_ebp/models/account_move.py @@ -5,63 +5,37 @@ # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp.osv import fields, osv -from openerp.tools.translate import _ +from openerp import _, api, fields, models +from openerp.exceptions import Warning as UserError -class account_move(osv.osv): - _inherit = "account.move" +class AccountMove(models.Model): + _inherit = 'account.move' - # Columns section - def _export_name(self, cr, uid, ids, field_name, arg, context=None): - result = {} - for move in self.browse(cr, uid, ids, context=context): - result[move.id] = move.exported_ebp_id\ - and 'export_' + str(move.exported_ebp_id.id) or '' - return result - - _columns = { - 'exported_ebp_id': fields.many2one( - 'ebp.export', 'Transfer id', - help="""Indicates whether the move has already been exported""" - """ to EBP or not. It is changed automatically."""), - 'exported_ebp': fields.function( - _export_name, type='char', string='export id', store=False), - } + # Column Section + ebp_export_id = fields.Many2one( + comodel_name='ebp.export', old_name='exported_ebp_id', + string='EBP Export', copy=False, + help="Indicates whether the move has already been exported" + " to EBP or not. It is changed automatically.") # Override section - def write(self, cr, uid, ids, vals, context=None): - """Refuse to change changes exported Moves""" - if 'exported_ebp_id' not in vals: - exported_move_ids = self.search( - cr, uid, [('exported_ebp_id', '!=', False), ('id', 'in', ids)]) - if exported_move_ids: - exported_moves = self.browse( - cr, uid, exported_move_ids, context=context) - raise osv.except_osv( - _('Exported move!'), - _('You cannot modify exported moves: %s!') - % ', '.join([m.name for m in exported_moves])) - return super(osv.osv, self).write(cr, uid, ids, vals, context=context) - - def unlink(self, cr, uid, ids, context=None, check=True): - """Refuse to delete exported Moves""" - exported_move_ids = self.search( - cr, uid, [('exported_ebp_id', '!=', False), ('id', 'in', ids)]) - if exported_move_ids: - exported_moves = self.browse( - cr, uid, exported_move_ids, context=context) - raise osv.except_osv( - _('Exported move!'), - _('You cannot delete exported moves: %s!') + @api.multi + def write(self, vals): + self._check_exported_moves() + return super(AccountMove, self).write(vals) + + @api.multi + def unlink(self): + self._check_exported_moves() + return super(AccountMove, self).unlink() + + # Custom section + @api.multi + def _check_exported_moves(self): + exported_moves =\ + self.filtered(lambda x: x.ebp_export_id.id is not False) + if exported_moves: + raise UserError(_( + "You cannot modify or delete exported moves: %s!") % ', '.join([m.name for m in exported_moves])) - return super(account_move, self).unlink(cr, uid, ids, context) - - def copy(self, cr, uid, pId, default=None, context=None): - if not default: - default = {} - default.update({ - 'exported_ebp_id': False, - }) - return super(account_move, self).copy( - cr, uid, pId, default, context=context) diff --git a/account_export_ebp/models/account_tax_code.py b/account_export_ebp/models/account_tax_code.py index 4adbe81..1d1bd11 100644 --- a/account_export_ebp/models/account_tax_code.py +++ b/account_export_ebp/models/account_tax_code.py @@ -5,54 +5,25 @@ # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp.osv import fields -from openerp.osv.orm import Model +from openerp import api, fields, models -class account_tax_code(Model): - _inherit = 'account.tax.code' - - def _get_nb_moves(self, cr, uid, ids, name, arg, context=None): - res = {} - aml_obj = self.pool.get('account.move.line') - for aId in ids: - aml_ids = aml_obj.search(cr, uid, [ - ('tax_code_id', '=', aId), ('date', '>=', '01/12/2012')], - context=context) - res[aId] = len(aml_ids) - return res - def _search_nb_moves(self, cr, uid, obj, name, args, context=None): - if not args: - return [] - query, query_args = self._get_search_moves_query( - cr, uid, args, overdue_only=False, context=context) - cr.execute(query, query_args) - res = cr.fetchall() - if not res: - return [('id', '=', '0')] - return [('id', 'in', [x[0] for x in res])] +class AccountTaxCode(models.Model): + _inherit = 'account.tax.code' # Columns section - _columns = { - 'ref_nb': fields.char( - 'Tax Code\'s Account suffix in EBP', size=4, - help="""When exporting Entries to EBP, this suffix will be""" - """ appended to the Account Number to make it a new Account."""), - 'nb_moves': fields.function( - _get_nb_moves, string='Number of moves', - fnct_search=_search_nb_moves, type='integer', - help="Number of account moves for this tax code"), - } + ebp_suffix = fields.Char( + string="Suffix in EBP", oldname="ref_nb", + help="When exporting Entries to EBP, this suffix will be" + " appended to the Account Number to make it a new Account.") + + move_line_qty = fields.Integer( + compute='_compute_move_line_qty', + string='Quantity of Account Move Lines', + help="Number of account moves for this partner") - # Private section - def _get_search_moves_query( - self, cr, uid, args, overdue_only=False, context=None): - having_where_clause = ' AND '.join( - map(lambda x: '(COUNT(*) %s %%s)' % (x[1]), args)) - having_values = [x[2] for x in args] - return "SELECT tax_code_id, count(*) \ - FROM account_move_line \ - WHERE date >= '01/12/2012' \ - GROUP BY tax_code_id \ - HAVING " + having_where_clause, having_values + @api.multi + def _compute_move_line_qty(self): + pass + # AccountMoveLine = self.env['account.move.line'] diff --git a/account_export_ebp/models/ebp_export.py b/account_export_ebp/models/ebp_export.py index 95966e4..160b1cc 100644 --- a/account_export_ebp/models/ebp_export.py +++ b/account_export_ebp/models/ebp_export.py @@ -29,7 +29,7 @@ def _get_name(self, cr, uid, ids, name, args, context): 'exported_accounts': fields.integer( 'Number of accounts exported', readonly=True), 'exported_moves_ids': fields.one2many( - 'account.move', 'exported_ebp_id', 'Exported Moves', + 'account.move', 'ebp_export_id', 'Exported Moves', readonly=True), 'data_moves': fields.binary( 'Moves file', readonly=True), diff --git a/account_export_ebp/models/res_company.py b/account_export_ebp/models/res_company.py index 4101021..6c64705 100644 --- a/account_export_ebp/models/res_company.py +++ b/account_export_ebp/models/res_company.py @@ -5,41 +5,20 @@ # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp.osv import fields -from openerp.osv.orm import Model +from openerp import api, fields, models -class res_company(Model): - """Add parameters to export accounting moves to EBP's software""" + +class ResCompany(models.Model): _inherit = 'res.company' - # Columns section - def _get_ebp_trigram(self, cr, uid, ids, field_name, arg, context=None): - res = {} - for rc in self.browse(cr, uid, ids, context=context): - if rc.fiscal_type in ['fiscal_child', 'fiscal_mother']: - res[rc.id] = rc.code - else: - res[rc.id] = '' - return res + # Column Section + ebp_trigram = fields.Char( + string='EBP Trigram', compute='_compute_ebp_trigram', store=True) - _columns = { - 'ebp_trigram': fields.function( - _get_ebp_trigram, type='char', string='EBP Trigram', store=True), - 'ebp_uri': fields.char( - 'EBP Share URI', size=256, - help="""The URI of the network share containing the company's""" - """ EBP folder. Format: smb://SERVER/SHARE/DIR"""), - 'ebp_domain': fields.char( - 'EBP User Domain', size=256, - help="""The domain of the user to access the company's EBP""" - """ folder."""), - 'ebp_username': fields.char( - 'EBP User Name', size=256, - help="""The name of the user to access the company's EBP""" - """ folder."""), - 'ebp_password': fields.char( - 'EBP User Password', size=256, - help="""The password of the user to access the company's""" - """ EBP folder."""), - } + @api.multi + @api.depends('fiscal_type') + def _compute_ebp_trigram(self): + for company in self.filtered( + lambda x: x.fiscal_type in ['fiscal_child', 'fiscal_mother']): + company.ebp_trigram = company.code diff --git a/account_export_ebp/models/res_partner.py b/account_export_ebp/models/res_partner.py index b4852da..880ae08 100644 --- a/account_export_ebp/models/res_partner.py +++ b/account_export_ebp/models/res_partner.py @@ -5,73 +5,92 @@ # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp.osv import fields -from openerp.osv.orm import Model +from openerp import _, api, fields, models +from openerp.exceptions import Warning as UserError -class res_partner(Model): + +class ResPartner(models.Model): _inherit = 'res.partner' # Columns section - def _nb_moves(self, cr, uid, ids, name, arg, context=None): - res = {} - aml_obj = self.pool.get('account.move.line') - for aId in ids: - aml_ids = aml_obj.search(cr, uid, [ - ('partner_id', '=', aId), ('date', '>=', '01/12/2012')], - context=context) - res[aId] = len(aml_ids) - return res + ebp_suffix = fields.Char( + string="Suffix in EBP", oldname="ref_nb", + help="When exporting Entries to EBP, this suffix will be" + " appended to the Account Number to make it a Partner Account.") - def _search_nb_moves(self, cr, uid, obj, name, args, context=None): - if not args: - return [] - query, query_args = self._get_search_moves_query( - cr, uid, args, overdue_only=False, context=context) - cr.execute(query, query_args) - res = cr.fetchall() - if not res: - return [('id', '=', '0')] - return [('id', 'in', [x[0] for x in res])] + move_line_qty = fields.Integer( + compute='_compute_move_line_qty', + string='Quantity of Account Move Lines', + help="Number of account moves for this partner") - _columns = { + # Columns section + @api.multi + def _compute_move_line_qty(self): + AccountMoveLine = self.env['account.move.line'] + # for aId in ids: + # aml_ids = aml_obj.search(cr, uid, [ + # ('partner_id', '=', aId), ('date', '>=', '01/12/2012')], + # context=context) + # res[aId] = len(aml_ids) + # return res + # TODO +# +# Search Section + # def _search_ean_duplicates_exist(self, operator, operand): + # products = self.search([]) + # res = products._get_ean_duplicates() + # if operator == '=' and operand is True: + # product_ids = res.keys() + # elif operator == '=' and operand is False: + # product_ids = list(set(products.ids) - set(res.keys())) + # else: + # raise UserError(_( + # "Operator '%s' not implemented.") % (operator)) + # return [('id', 'in', product_ids)] +# +# + # def _search_move_line_qty(self, cr, uid, obj, name, args, context=None): + # if not args: + # return [] + # query, query_args = self._get_search_moves_query( + # cr, uid, args, overdue_only=False, context=context) + # cr.execute(query, query_args) + # res = cr.fetchall() + # if not res: + # return [('id', '=', '0')] + # return [('id', 'in', [x[0] for x in res])] +# + # _columns = { # Partner's account number in EBP - 'ref_nb': fields.char( - 'Partner\'s Account suffix in EBP', - help="""When exporting Entries to EBP, this suffix will be""" - """ appended to the Account Number to make it a Partner""" - """ Account."""), - 'nb_moves': fields.function( - _nb_moves, string='Number of moves', - fnct_search=_search_nb_moves, type='integer', - help="Number of account moves for this partner"), - } - +# + # } +# # Constraints section - _sql_constraints = [ - ( - 'partner_suffix_uniq', - 'unique (ref_nb, company_id)', - 'The partner suffix must be unique per company!') - ] - + # _sql_constraints = [ + # ( + # 'partner_suffix_uniq', + # 'unique (ref_nb, company_id)', + # 'The partner suffix must be unique per company!') + # ] +# # Overloading section - def write(self, cr, uid, ids, vals, context=None): - ref_nb = vals.get('ref_nb', False) - if ref_nb: - vals['ref_nb'] = ref_nb.upper() - return super(res_partner, self).write( - cr, uid, ids, vals, context=context) - + # def write(self, cr, uid, ids, vals, context=None): + # ref_nb = vals.get('ref_nb', False) + # if ref_nb: + # vals['ref_nb'] = ref_nb.upper() + # return super(res_partner, self).write( + # cr, uid, ids, vals, context=context) +# # Private section - def _get_search_moves_query( - self, cr, uid, args, overdue_only=False, context=None): - having_where_clause = ' AND '.join( - map(lambda x: '(COUNT(*) %s %%s)' % (x[1]), args)) - having_values = [x[2] for x in args] - return """ - SELECT partner_id, count(*) - FROM account_move_line - WHERE date >= '01/12/2012' - GROUP BY partner_id - HAVING """ + having_where_clause, having_values + # def _get_search_moves_query( + # self, cr, uid, args, overdue_only=False, context=None): + # having_where_clause = ' AND '.join( + # map(lambda x: '(COUNT(*) %s %%s)' % (x[1]), args)) + # having_values = [x[2] for x in args] + # return """ + # SELECT partner_id, count(*) + # FROM account_move_line + # WHERE date >= '01/12/2012' + # GROUP BY partner_id + # HAVING """ + having_where_clause, having_values diff --git a/account_export_ebp/views/view_account_account.xml b/account_export_ebp/views/view_account_account.xml index 511283c..71bf19f 100644 --- a/account_export_ebp/views/view_account_account.xml +++ b/account_export_ebp/views/view_account_account.xml @@ -11,7 +11,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + diff --git a/account_export_ebp/views/view_account_export_ebp.xml b/account_export_ebp/views/view_account_export_ebp.xml index 14901b6..03588f6 100644 --- a/account_export_ebp/views/view_account_export_ebp.xml +++ b/account_export_ebp/views/view_account_export_ebp.xml @@ -24,7 +24,6 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - diff --git a/account_export_ebp/views/view_account_fiscalyear.xml b/account_export_ebp/views/view_account_fiscalyear.xml deleted file mode 100644 index 2089304..0000000 --- a/account_export_ebp/views/view_account_fiscalyear.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - account.fiscalyear - - - - - - - - - diff --git a/account_export_ebp/views/view_account_move.xml b/account_export_ebp/views/view_account_move.xml index 2673de3..61754e8 100644 --- a/account_export_ebp/views/view_account_move.xml +++ b/account_export_ebp/views/view_account_move.xml @@ -11,7 +11,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + @@ -20,7 +20,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + @@ -32,7 +32,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + domain="[('ebp_export_id', '=', False)]" help="Journal Entries not yet exported to EBP" /> diff --git a/account_export_ebp/views/view_account_tax_code.xml b/account_export_ebp/views/view_account_tax_code.xml index 0779d0b..8e926e1 100644 --- a/account_export_ebp/views/view_account_tax_code.xml +++ b/account_export_ebp/views/view_account_tax_code.xml @@ -12,12 +12,12 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). @@ -28,7 +28,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + @@ -38,7 +38,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + @@ -49,8 +49,8 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - + + diff --git a/account_export_ebp/views/view_res_company.xml b/account_export_ebp/views/view_res_company.xml deleted file mode 100644 index e22e4d2..0000000 --- a/account_export_ebp/views/view_res_company.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - res.company - - - - - - - - - - - - - - diff --git a/account_export_ebp/views/view_res_partner.xml b/account_export_ebp/views/view_res_partner.xml index ef7d67a..350fd21 100644 --- a/account_export_ebp/views/view_res_partner.xml +++ b/account_export_ebp/views/view_res_partner.xml @@ -13,7 +13,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + @@ -27,12 +27,12 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). @@ -49,8 +49,8 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - + + diff --git a/account_export_ebp/wizard/wizard_add_suffix.py b/account_export_ebp/wizard/wizard_add_suffix.py index 5bfbfe8..024df9b 100644 --- a/account_export_ebp/wizard/wizard_add_suffix.py +++ b/account_export_ebp/wizard/wizard_add_suffix.py @@ -38,7 +38,7 @@ def affect_suffix(self, cr, uid, ids, context=None): for line in suf.line_ids: if line.suffix: rp_obj.write(cr, uid, [line.partner_id.id], { - 'ref_nb': line.suffix, + 'ebp_suffix': line.suffix, }, context=context) return True @@ -54,17 +54,17 @@ def default_get(self, cr, uid, pFields, context=None): return res existing_suffixes = {} sql_req = """ - SELECT rp.company_id, rp.ref_nb from res_partner rp - WHERE ref_nb is not Null """ + SELECT rp.company_id, rp.ebp_suffix from res_partner rp + WHERE ebp_suffix is not Null """ cr.execute(sql_req) result = cr.dictfetchall() for item in result: existing_suffixes.setdefault(item['company_id'], []) - existing_suffixes[item['company_id']] += [item['ref_nb']] + existing_suffixes[item['company_id']] += [item['ebp_suffix']] for partner in rp_obj.browse(cr, uid, partner_ids, context=context): - if partner.ref_nb: - suffix = partner.ref_nb + if partner.ebp_suffix: + suffix = partner.ebp_suffix else: suffix = self._get_suffix( partner.name, existing_suffixes.get( diff --git a/account_export_ebp/wizard/wizard_ebp.py b/account_export_ebp/wizard/wizard_ebp.py index eb31d44..c9befb0 100644 --- a/account_export_ebp/wizard/wizard_ebp.py +++ b/account_export_ebp/wizard/wizard_ebp.py @@ -7,11 +7,10 @@ import base64 import cStringIO -import codecs import logging -from openerp.tools.translate import _ from openerp.osv import fields, osv +from openerp.tools.translate import _ _logger = logging.getLogger(__name__) @@ -20,18 +19,12 @@ except ImportError: _logger.debug("account_export_ebp - 'unidecode' librairy not found") -try: - import smbc -except: - _logger.debug("account_export_ebp - 'smbc' librairy not found") - smbc = False - # TODO # We should write to a temporary file instead, for security and reliability. # We should raise a clean exception if something goes wrong. -class account_export_ebp(osv.TransientModel): +class AccountExportEbp(osv.TransientModel): _name = "account.export.ebp" # Columns Section @@ -70,11 +63,6 @@ class account_export_ebp(osv.TransientModel): 'ignore_exported': fields.boolean( 'Ignore moves already exported', help="Check this box unless you want to re-export moves to EBP"), - 'download_file': fields.boolean( - 'Download file', help="""Check this box if you want to""" - """ download the result as a file on your computer. Otherwise,""" - """ the file will be saved at the place defined in the company""" - """ settings."""), 'data_moves': fields.binary('File', readonly=True), 'data_accounts': fields.binary('File', readonly=True), 'data_balance': fields.binary('File', readonly=True), @@ -105,7 +93,7 @@ def _get_empty_suffixes_partner(self, cr, uid, context=None): aml_obj = self.pool.get('account.move.line') rp_ids = rp_obj.search( - cr, uid, [('ref_nb', '=', False)], context=context) + cr, uid, [('ebp_suffix', '=', False)], context=context) aml_ids = aml_obj.search(cr, uid, [ ('date', '>=', '01/12/2012'), ('partner_id', 'in', rp_ids)], context=context) @@ -119,7 +107,7 @@ def _get_empty_suffixes_tax(self, cr, uid, context=None): aml_obj = self.pool.get('account.move.line') atc_ids = atc_obj.search( - cr, uid, [('ref_nb', '=', False)], context=context) + cr, uid, [('ebp_suffix', '=', False)], context=context) aml_ids = aml_obj.search(cr, uid, [ ('date', '>=', '01/12/2012'), ('tax_code_id', 'in', atc_ids)], context=context) @@ -134,7 +122,6 @@ def _get_empty_suffixes_tax(self, cr, uid, context=None): 'ignore_draft': lambda * a: True, 'company_suffix': lambda * a: True, 'partner_accounts': lambda * a: True, - 'download_file': lambda * a: True, 'tax_code_suffix': lambda * a: True, 'state': 'export_ebp', 'empty_suffixes_partner': _get_empty_suffixes_partner, @@ -144,11 +131,7 @@ def _get_empty_suffixes_tax(self, cr, uid, context=None): def export(self, cr, uid, ids, context=None): if context is None: context = {} - this = self.browse(cr, uid, ids, context=context)[0] - if this.download_file: - return self._download(cr, uid, ids, context=context) - else: - return self._save(cr, uid, ids, context=context) + return self._download(cr, uid, ids, context=context) def _download(self, cr, uid, ids, context=None): export_obj = self.pool.get('ebp.export') @@ -194,44 +177,6 @@ def _download(self, cr, uid, ids, context=None): 'target': 'new', } - def _save(self, cr, uid, ids, context): - if context is None: - context = {} - - # Stream writer to convert Unicode to Windows Latin-1 - win_writer = codecs.getwriter('cp1252') - - # Connect to the network share - company = self.pool.get('res.users').browse( - cr, uid, uid, context=context).company_id - data = {'form': self.read(cr, uid, ids, context=context)[0]} - fiscalyear = self.pool.get('account.fiscalyear').browse( - cr, uid, data['form']['fiscalyear_id'][0], context) - - path = '%s/Compta.%s' % (company.ebp_uri, fiscalyear.ebp_nb) - _logger.debug("Connecting to %s as user %s, domain %s" % ( - path, fiscalyear.company_id.ebp_username, - fiscalyear.company_id.ebp_domain)) - win_share = smbc.Context( - auth_fn=lambda server, share, workgroup, username, password: ( - fiscalyear.company_id.ebp_domain, - fiscalyear.company_id.ebp_username, - fiscalyear.company_id.ebp_password)) - moves_file = win_writer(win_share.creat('%s/ECRITURES.TXT' % path)) - account_file = win_writer(win_share.creat('%s/COMPTES.TXT' % path)) - balance_file = win_writer(win_share.creat('%s/BALANCES.TXT' % path)) - self._export( - cr, uid, ids, moves_file, account_file, context=None) - - # Close the move summaries file - moves_file.close() - account_file.close() - balance_file.close() -# _logger.debug( -# """%d line(s) representing %d move(s) exported to""" -# """ ECRITURES.TXT in %s - %d move(s) ignored""" % ( -# l, len(exported_move_ids), path, len(ignored_move_ids))) - def _export( self, cr, uid, ids, moves_file, account_file, balance_file, context=None): @@ -335,7 +280,7 @@ def normalize(text): data['form']['fiscalyear_id'][0]) # Ignore moves already exported ignore_exported = ( - data['form']['ignore_exported'] and move.exported_ebp_id) + data['form']['ignore_exported'] and move.ebp_export_id) # Skip to next move if this one should be ignored if ignore_draft or ignore_year or\ ignore_exported or ignore_unchecked: @@ -366,15 +311,15 @@ def normalize(text): .is_intercompany_trade_fiscal_company: account_nb = account_nb + line.company_id.ebp_trigram if data['form']['partner_accounts'] and line.partner_id and\ - line.partner_id.ref_nb and\ + line.partner_id.ebp_suffix and\ line.account_id.type in ('payable', 'receivable')\ and not line.account_id\ .is_intercompany_trade_fiscal_company: # Partner account - account_nb = account_nb + line.partner_id.ref_nb - if (tax_code_suffix and line.account_id.export_tax_code): - if line.tax_code_id.ref_nb: - account_nb = account_nb + line.tax_code_id.ref_nb + account_nb = account_nb + line.partner_id.ebp_suffix + if (tax_code_suffix and line.account_id.ebp_export_tax_code): + if line.tax_code_id.ebp_suffix: + account_nb = account_nb + line.tax_code_id.ebp_suffix else: if not line.account_id.ebp_code_no_tax: raise osv.except_osv( @@ -454,7 +399,7 @@ def normalize(text): # we want to export may be partner specific if account_nb not in accounts_data.keys(): if (data['form']['partner_accounts'] and - line.partner_id and line.partner_id.ref_nb and + line.partner_id and line.partner_id.ebp_suffix and line.account_id.type in ('payable', 'receivable')): # Partner account # Get the default address @@ -479,8 +424,8 @@ def normalize(text): 'fax': partner.fax or '', } elif (tax_code_suffix and - line.account_id.export_tax_code and - line.tax_code_id.ref_nb): + line.account_id.ebp_export_tax_code and + line.tax_code_id.ebp_suffix): accounts_data[account_nb] = { 'name': ( normalize(line.account_id.name) + @@ -597,7 +542,7 @@ def normalize(text): 'description': data['form']['description'], }, context=context) self.pool.get('account.move').write(cr, uid, exported_move_ids, { - 'exported_ebp_id': export_id, + 'ebp_export_id': export_id, }, context=context) # Header for Balance File diff --git a/account_export_ebp/wizard/wizard_unexport.py b/account_export_ebp/wizard/wizard_unexport.py index 519a66c..0db237e 100644 --- a/account_export_ebp/wizard/wizard_unexport.py +++ b/account_export_ebp/wizard/wizard_unexport.py @@ -23,7 +23,7 @@ def unexport(self, cr, uid, ids, context=None): unexport_ids = context.get('active_ids', False) am_obj = self.pool.get('account.move') am_obj.write(cr, uid, unexport_ids, { - 'exported_ebp_id': False, + 'ebp_export_id': False, }, context=context) # TODO: find the file in ebp.export model and remove the move lines return ids From 2b2c737aa5d6f3cc71c43868e03c986364ae26e0 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Fri, 12 Oct 2018 16:56:07 +0200 Subject: [PATCH 02/11] [WIP] --- account_export_ebp/__openerp__.py | 6 +- account_export_ebp/models/ebp_export.py | 126 ++-- account_export_ebp/views/menu.xml | 2 +- .../views/view_account_move.xml | 14 +- account_export_ebp/views/view_ebp_export.xml | 38 +- account_export_ebp/views/view_res_partner.xml | 26 +- account_export_ebp/wizard/__init__.py | 6 +- .../view_wizard_ebp_export.xml} | 0 .../view_wizard_ebp_unexport.xml} | 11 +- .../view_wizard_res_partner_add_suffix.xml} | 12 +- account_export_ebp/wizard/wizard_ebp.py | 614 ----------------- .../wizard/wizard_ebp_export.py | 632 ++++++++++++++++++ .../wizard/wizard_ebp_unexport.py | 20 + ...ix.py => wizard_res_partner_add_suffix.py} | 4 +- .../wizard/wizard_res_partner_add_suffix.xml | 36 + account_export_ebp/wizard/wizard_unexport.py | 29 - 16 files changed, 822 insertions(+), 754 deletions(-) rename account_export_ebp/{views/view_account_export_ebp.xml => wizard/view_wizard_ebp_export.xml} (100%) rename account_export_ebp/{views/view_account_unexport_ebp.xml => wizard/view_wizard_ebp_unexport.xml} (67%) rename account_export_ebp/{views/view_account_add_suffix.xml => wizard/view_wizard_res_partner_add_suffix.xml} (71%) delete mode 100644 account_export_ebp/wizard/wizard_ebp.py create mode 100644 account_export_ebp/wizard/wizard_ebp_export.py create mode 100644 account_export_ebp/wizard/wizard_ebp_unexport.py rename account_export_ebp/wizard/{wizard_add_suffix.py => wizard_res_partner_add_suffix.py} (98%) create mode 100644 account_export_ebp/wizard/wizard_res_partner_add_suffix.xml delete mode 100644 account_export_ebp/wizard/wizard_unexport.py diff --git a/account_export_ebp/__openerp__.py b/account_export_ebp/__openerp__.py index f83e2e0..fcc1d15 100644 --- a/account_export_ebp/__openerp__.py +++ b/account_export_ebp/__openerp__.py @@ -49,10 +49,10 @@ 'security/ir_model_access.yml', 'security/ir_rule.xml', 'views/menu.xml', + 'wizard/view_wizard_res_partner_add_suffix.xml', + 'wizard/view_wizard_ebp_unexport.xml', + # 'wizard/view_wizard_ebp_export.xml', 'views/view_account_account.xml', - 'views/view_account_add_suffix.xml', - 'views/view_account_export_ebp.xml', - 'views/view_account_unexport_ebp.xml', 'views/view_account_journal.xml', 'views/view_account_move.xml', 'views/view_account_tax_code.xml', diff --git a/account_export_ebp/models/ebp_export.py b/account_export_ebp/models/ebp_export.py index 160b1cc..270d125 100644 --- a/account_export_ebp/models/ebp_export.py +++ b/account_export_ebp/models/ebp_export.py @@ -5,50 +5,82 @@ # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp.osv import fields -from openerp.osv.orm import Model - - -class ebp_export(Model): - _name = "ebp.export" - - def _get_name(self, cr, uid, ids, name, args, context): - return {x: 'export_' + str(x) for x in ids} - - _columns = { - 'company_id': fields.many2one( - 'res.company', 'Company', required=True, readonly=True), - 'fiscalyear_id': fields.many2one( - 'account.fiscalyear', 'Fiscal year', required=True, readonly=True), - 'exported_moves': fields.integer( - 'Number of moves exported', readonly=True), - 'ignored_moves': fields.integer( - 'Number of moves ignored', readonly=True), - 'exported_lines': fields.integer( - 'Number of lines exported', readonly=True), - 'exported_accounts': fields.integer( - 'Number of accounts exported', readonly=True), - 'exported_moves_ids': fields.one2many( - 'account.move', 'ebp_export_id', 'Exported Moves', - readonly=True), - 'data_moves': fields.binary( - 'Moves file', readonly=True), - 'data_accounts': fields.binary( - 'Accounts file', readonly=True), - 'data_balance': fields.binary( - 'Balance file', readonly=True), - 'date': fields.date( - 'Date', required=True, readonly=True), - 'name': fields.function( - _get_name, 'Name', type='char', store=True, readonly=True), - 'description': fields.text( - 'Description', readonly=True, - help="Extra Description for Accountant Manager."), - } - _defaults = { - 'exported_moves': lambda * a: 0, - 'ignored_moves': lambda * a: 0, - 'exported_lines': lambda * a: 0, - 'exported_accounts': lambda * a: 0, - 'date': lambda * a: fields.date.today() - } +from openerp import _, api, fields, models + + +class EbpExport(models.Model): + _name = 'ebp.export' + _order = 'date desc' + + # Column Section + company_id = fields.Many2one( + comodel_name='res.company', string='Company', required=True, + readonly=True) + + fiscalyear_id = fields.Many2one( + comodel_name='account.fiscalyear', string='Fiscal year', required=True, + readonly=True) + + date = fields.Datetime( + 'Date', required=True, readonly=True) + + name = fields.Char( + compute='_compute_name', string='Name', store=True, readonly=True) + + description = fields.Text( + string='Description', readonly=True, + help="Extra Description for Accountant Manager.") + + exported_move_qty = fields.Integer( + oldname='exported_moves' + 'Quantity of Moves Exported', readonly=True) + + exported_account_qty = fields.Integer( + oldname='exported_accounts', + string='Quantity of accounts exported', readonly=True) + + exported_moves_ids = fields.One2many( + comodel_name='account.move', inverse_name='ebp_export_id', + string='Exported Moves', readonly=True) + + data_moves = fields.Binary( + string='Moves file', readonly=True) + + data_accounts = fields.Binary( + string='Accounts file', readonly=True) + + data_balance = fields.Binary( + string='Balance file', readonly=True) + + file_name_moves = fields.Char( + readonly=True, compute='_compute_file_name_moves') + + file_name_accounts = fields.Char( + readonly=True, compute='_compute_file_name_accounts') + + file_name_balance = fields.Char( + readonly=True, compute='_compute_file_name_balance') + + # Compute Section + @api.multi + def _compute_name(self): + for export in self: + export.name = 'export_%d' % export.id + + @api.multi + def _compute_file_name_moves(self): + for export in self: + export.file_name_moves =\ + 'export_%d_%s.csv' % (export.id, _("MOVES")) + + @api.multi + def _compute_file_name_accounts(self): + for export in self: + export.file_name_accounts =\ + 'export_%d_%s.csv' % (export.id, _("ACCOUNTS")) + + @api.multi + def _compute_file_name_balance(self): + for export in self: + export.file_name_balance =\ + 'export_%d_%s.csv' % (export.id, _("BALANCE")) diff --git a/account_export_ebp/views/menu.xml b/account_export_ebp/views/menu.xml index ad689ab..ce86c36 100644 --- a/account_export_ebp/views/menu.xml +++ b/account_export_ebp/views/menu.xml @@ -6,7 +6,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). --> - - - + + + Cancel EBP Export client_action_multi - + action account.move diff --git a/account_export_ebp/views/view_ebp_export.xml b/account_export_ebp/views/view_ebp_export.xml index 48ed791..434a4f6 100644 --- a/account_export_ebp/views/view_ebp_export.xml +++ b/account_export_ebp/views/view_ebp_export.xml @@ -1,4 +1,10 @@ + + @@ -6,10 +12,8 @@ - - - - + + @@ -17,13 +21,14 @@ ebp.export - + - - - - + + + + + @@ -32,17 +37,15 @@ ebp.export -
+

- - - - + + @@ -65,11 +68,10 @@ tree,form - - diff --git a/account_export_ebp/views/view_res_partner.xml b/account_export_ebp/views/view_res_partner.xml index 350fd21..259f633 100644 --- a/account_export_ebp/views/view_res_partner.xml +++ b/account_export_ebp/views/view_res_partner.xml @@ -24,27 +24,19 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - - - - - - - - + res.partner @@ -58,7 +50,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + Partner Suffixes ir.actions.act_window res.partner @@ -69,16 +61,16 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - - Add EBP Suffix + + + Add EBP Suffixes client_action_multi - + action res.partner diff --git a/account_export_ebp/wizard/__init__.py b/account_export_ebp/wizard/__init__.py index 2eb4230..4efe501 100644 --- a/account_export_ebp/wizard/__init__.py +++ b/account_export_ebp/wizard/__init__.py @@ -1,4 +1,4 @@ # coding: utf-8 -from . import wizard_ebp -from . import wizard_unexport -from . import wizard_add_suffix +from . import wizard_ebp_export +from . import wizard_ebp_unexport +from . import wizard_res_partner_add_suffix diff --git a/account_export_ebp/views/view_account_export_ebp.xml b/account_export_ebp/wizard/view_wizard_ebp_export.xml similarity index 100% rename from account_export_ebp/views/view_account_export_ebp.xml rename to account_export_ebp/wizard/view_wizard_ebp_export.xml diff --git a/account_export_ebp/views/view_account_unexport_ebp.xml b/account_export_ebp/wizard/view_wizard_ebp_unexport.xml similarity index 67% rename from account_export_ebp/views/view_account_unexport_ebp.xml rename to account_export_ebp/wizard/view_wizard_ebp_unexport.xml index 615382f..787c4b6 100644 --- a/account_export_ebp/views/view_account_unexport_ebp.xml +++ b/account_export_ebp/wizard/view_wizard_ebp_unexport.xml @@ -6,27 +6,26 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). --> - - account.unexport.ebp + + wizard.ebp.unexport

The export will be canceled for the selected moves.

Be sure to delete the corresponding lines in EBP.

-
- + Cancel EBP Export ir.actions.act_window - account.unexport.ebp + wizard.ebp.unexport form form - new diff --git a/account_export_ebp/views/view_account_add_suffix.xml b/account_export_ebp/wizard/view_wizard_res_partner_add_suffix.xml similarity index 71% rename from account_export_ebp/views/view_account_add_suffix.xml rename to account_export_ebp/wizard/view_wizard_res_partner_add_suffix.xml index b6845b5..fd9695d 100644 --- a/account_export_ebp/views/view_account_add_suffix.xml +++ b/account_export_ebp/wizard/view_wizard_res_partner_add_suffix.xml @@ -6,8 +6,8 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). --> - - account.add.suffix + + wizard.res.partner.add.suffix
@@ -24,14 +24,12 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - Add EBP Suffix + + Add EBP Suffixes ir.actions.act_window - account.add.suffix + wizard.res.partner.add.suffix form form - - {} new diff --git a/account_export_ebp/wizard/wizard_ebp.py b/account_export_ebp/wizard/wizard_ebp.py deleted file mode 100644 index c9befb0..0000000 --- a/account_export_ebp/wizard/wizard_ebp.py +++ /dev/null @@ -1,614 +0,0 @@ -# coding: utf-8 -# Copyright (C) 2010 - 2015: Numérigraphe SARL -# Copyright (C) 2015 - Today: GRAP (http://www.grap.coop) -# @author: Julien WESTE -# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -import base64 -import cStringIO -import logging - -from openerp.osv import fields, osv -from openerp.tools.translate import _ - -_logger = logging.getLogger(__name__) - -try: - from unidecode import unidecode -except ImportError: - _logger.debug("account_export_ebp - 'unidecode' librairy not found") - -# TODO -# We should write to a temporary file instead, for security and reliability. -# We should raise a clean exception if something goes wrong. - - -class AccountExportEbp(osv.TransientModel): - _name = "account.export.ebp" - - # Columns Section - _columns = { - 'name_moves': fields.char('File Name', readonly=True), - 'name_accounts': fields.char('File Name', readonly=True), - 'name_balance': fields.char('File Name', readonly=True), - 'fiscalyear_id': fields.many2one( - 'account.fiscalyear', 'Fiscal year', - required=True, - help='Only the moves in this fiscal will be exported'), - 'company_suffix': fields.boolean( - 'Append company\'s code to accounts', - help="""When this is checked, the company's code will be""" - """ appended to the receivable and payable accounts' numbers in""" - """ the exported files on every move line."""), - 'partner_accounts': fields.boolean( - 'Append partners\' code to accounts', - help="""When this is checked, the partner's special code will""" - """ be appended to the receivable and payable accounts' numbers""" - """ in the exported files on every move line where a partner has""" - """ been specified."""), - 'tax_code_suffix': fields.boolean( - 'Export according to Tax Codes', - help="""Append Tax Code's suffix to account if the option is""" - """ checked in the account"""), - 'ignore_unchecked': fields.boolean( - 'Ignore unchecked moves', - help="""Please be aware that unchecked moves belong maybe some""" - """ errors."""), - 'ignore_draft': fields.boolean( - 'Ignore draft moves', - help="""Please be aware that draft moves do not not have a""" - """ move number attached to them. As a consequence, they might""" - """ not be imported correctly into EBP accounting software"""), - 'ignore_exported': fields.boolean( - 'Ignore moves already exported', - help="Check this box unless you want to re-export moves to EBP"), - 'data_moves': fields.binary('File', readonly=True), - 'data_accounts': fields.binary('File', readonly=True), - 'data_balance': fields.binary('File', readonly=True), - 'exported_moves': fields.integer( - 'Number of moves exported', readonly=True), - 'ignored_moves': fields.integer( - 'Number of moves ignored', readonly=True), - 'exported_lines': fields.integer( - 'Number of lines exported', readonly=True), - 'exported_accounts': fields.integer( - 'Number of accounts exported', readonly=True), - 'state': fields.selection([ - ('export_ebp', 'Prepare Export'), - ('export_ebp_end', 'Export Done'), - ('export_ebp_download', 'Ready to download') - ]), - 'empty_suffixes_partner': fields.boolean( - 'Empty Suffixes Partners', readonly=True), - 'empty_suffixes_tax': fields.boolean( - 'Empty Suffixes Taxes', readonly=True), - 'description': fields.text( - 'Description', help="Extra Description for Accountant Manager."), - } - - # Defaults Section - def _get_empty_suffixes_partner(self, cr, uid, context=None): - rp_obj = self.pool.get('res.partner') - aml_obj = self.pool.get('account.move.line') - - rp_ids = rp_obj.search( - cr, uid, [('ebp_suffix', '=', False)], context=context) - aml_ids = aml_obj.search(cr, uid, [ - ('date', '>=', '01/12/2012'), ('partner_id', 'in', rp_ids)], - context=context) - - if aml_ids: - return True - return False - - def _get_empty_suffixes_tax(self, cr, uid, context=None): - atc_obj = self.pool.get('account.tax.code') - aml_obj = self.pool.get('account.move.line') - - atc_ids = atc_obj.search( - cr, uid, [('ebp_suffix', '=', False)], context=context) - aml_ids = aml_obj.search(cr, uid, [ - ('date', '>=', '01/12/2012'), ('tax_code_id', 'in', atc_ids)], - context=context) - - if aml_ids: - return True - return False - - _defaults = { - 'ignore_unchecked': lambda * a: True, - 'ignore_exported': lambda * a: True, - 'ignore_draft': lambda * a: True, - 'company_suffix': lambda * a: True, - 'partner_accounts': lambda * a: True, - 'tax_code_suffix': lambda * a: True, - 'state': 'export_ebp', - 'empty_suffixes_partner': _get_empty_suffixes_partner, - 'empty_suffixes_tax': _get_empty_suffixes_tax, - } - - def export(self, cr, uid, ids, context=None): - if context is None: - context = {} - return self._download(cr, uid, ids, context=context) - - def _download(self, cr, uid, ids, context=None): - export_obj = self.pool.get('ebp.export') - if context is None: - context = {} - this = self.browse(cr, uid, ids)[0] - moves_file = cStringIO.StringIO() - account_file = cStringIO.StringIO() - balance_file = cStringIO.StringIO() - export_id = self._export( - cr, uid, ids, moves_file, account_file, balance_file, - context=context) - this.name_moves = "ECRITURES.csv" - this.name_accounts = "COMPTES.csv" - this.name_balance = "BALANCES.csv" - out_moves = base64.encodestring(moves_file.getvalue()) - out_accounts = base64.encodestring(account_file.getvalue()) - out_balance = base64.encodestring(balance_file.getvalue()) - moves_file.close() - account_file.close() - balance_file.close() - self.write(cr, uid, ids, { - 'state': 'export_ebp_download', - 'data_moves': out_moves, - 'data_accounts': out_accounts, - 'data_balance': out_balance, - 'name_moves': this.name_moves, - 'name_accounts': this.name_accounts, - 'name_balance': this.name_balance, - }, context=context) - export_obj.write(cr, uid, export_id, { - 'data_accounts': out_accounts, - 'data_balance': out_balance, - 'data_moves': out_moves, - }, context=context) - return { - 'type': 'ir.actions.act_window', - 'res_model': 'account.export.ebp', - 'view_mode': 'form', - 'view_type': 'form', - 'res_id': this.id, - 'views': [(False, 'form')], - 'target': 'new', - } - - def _export( - self, cr, uid, ids, moves_file, account_file, balance_file, - context=None): - """ - Export moves files usable by accounting software by EBP version - 3 and above. - - 2 files will be produced : - - a file of accounting moves (ECRITURES.TXT) - - a file of accounts (COMPTES.TXT) - If stored in the right folder, these files will automatically be - imported next time you open the folder in EBP. - - Lines with an amount of 0 are not ignored even though EBP complains - about them. This is to raise the attention of the person importing - them into EBP. Also, journals with a code which does not meet EBP's - requirements are not ignored. - - Returns a dictionary containing the number of moves and lines - exported and the number of moves ignored. - """ - - def normalize(text): - # Remove tricky characters from the string - if "\n;" in text: - text = text.replace("\n;", " ") - if ";" in text: - text = text.replace(";", " ") - if "," in text: - text = text.replace(",", " ") - if "\"" in text: - text = text.replace("\"", " ") - return text - - if context is None: - context = {} - export_obj = self.pool.get('ebp.export') - - data = {'form': self.read(cr, uid, ids, context=context)[0]} - _logger.debug("Form data: %s" % data['form']) - - # Read the EBP year number name from the selected fiscal year - fiscalyear = self.pool.get('account.fiscalyear').browse( - cr, uid, data['form']['fiscalyear_id'][0], context) - user_company = self.pool.get('res.users').browse( - cr, uid, uid, context=context).company_id - - # Sanity checks - if context.get('active_model', '') != 'account.move': - raise osv.except_osv( - _('Wrong Object'), - _("This wizard should only be used on accounting moves")) - - # dictionary to store accounts while we loop through move lines - accounts_data = {} - # Line counter - l = 0 - moves = self.pool.get('account.move').browse( - cr, uid, context.get('active_ids', []), context=context) - - is_analytic_column = False - for move in moves: - if move.company_id.ebp_trigram != '': - is_analytic_column = True - - # The move summaries will be written to a CSV file encoded in - # win-latin-1 - # TODO we should report errors more cleanly to the users here - - tax_code_suffix = data['form']['tax_code_suffix'] - exported_move_ids = [] - ignored_move_ids = [] - - # Move File header - move_line = ','.join([ - "Ligne", - "Date", - "Code journal", - "N° de compte", - "Intitulé", - "Pièce", - "Montant (associé au sens)", - "Sens", - "Échéance", - "Monnaie", - ]) - if is_analytic_column: - move_line += ',Poste analytique' - - moves_file.write(move_line) - moves_file.write('\r\n') - - for move in moves: - # Ignore draft moves unless the user asked for them - ignore_draft = ( - data['form']['ignore_draft'] and move.state == 'draft') - ignore_unchecked = ( - data['form']['ignore_unchecked'] and move.to_check) - # Ignore moves in other fiscal years - ignore_year = (move.period_id.fiscalyear_id.id != - data['form']['fiscalyear_id'][0]) - # Ignore moves already exported - ignore_exported = ( - data['form']['ignore_exported'] and move.ebp_export_id) - # Skip to next move if this one should be ignored - if ignore_draft or ignore_year or\ - ignore_exported or ignore_unchecked: - _logger.debug( - """Ignoring move %d - draft: %s, wrong year: %s,""" - """ exported: %s""" % ( - move.id, ignore_draft, ignore_year, ignore_exported)) - ignored_move_ids.append(move.id) - continue - - _logger.debug("Exporting move %d" % move.id) - # dictionary to summarize the lines of the move by account - moves_data = {} - for line in move.line_id: - _logger.debug("Examining move line %d" % line.id) - - if line.credit == line.debit: - _logger.debug( - """Move line %d has a sum equal to zero and will""" - """ not be exported.""" % line.id) - continue - # Make up the account number - account_nb = normalize(line.account_id.code) - if data['form']['company_suffix'] and line.company_id and\ - line.company_id.ebp_trigram and\ - line.account_id.type in ('payable', 'receivable')\ - and not line.account_id\ - .is_intercompany_trade_fiscal_company: - account_nb = account_nb + line.company_id.ebp_trigram - if data['form']['partner_accounts'] and line.partner_id and\ - line.partner_id.ebp_suffix and\ - line.account_id.type in ('payable', 'receivable')\ - and not line.account_id\ - .is_intercompany_trade_fiscal_company: - # Partner account - account_nb = account_nb + line.partner_id.ebp_suffix - if (tax_code_suffix and line.account_id.ebp_export_tax_code): - if line.tax_code_id.ebp_suffix: - account_nb = account_nb + line.tax_code_id.ebp_suffix - else: - if not line.account_id.ebp_code_no_tax: - raise osv.except_osv( - _('Incorrect Setting'), - _("The account %s - %s is set 'export with tax" - " suffix' but no tax suffix is defined for" - " the account.\n Move %s" % ( - line.account_id.code, - line.account_id.name, - line.move_id.name))) - else: - account_nb = account_nb +\ - line.account_id.ebp_code_no_tax - - # Check the most important fields are not above the maximum - # length so as not to export wrong data with catastrophic - # consequence - if not move.journal_id.ebp_code or\ - len(move.journal_id.ebp_code) == 0: - raise osv.except_osv( - _('Journal code Undefined'), - _("Journal '%s' has no EBP Code defined." % - move.journal_id.name)) - if len(move.journal_id.ebp_code) > 4: - raise osv.except_osv( - _('Journal code too long'), - _("Journal code '%s' is too long to be exported" - " to EBP." % move.journal_id.ebp_code)) - - # The docs from EBP state that account codes may be up to - # 15 characters but "EBP Comptabilité" v13 will refuse anything - # longer than 10 characters - if len(account_nb) > 10: - raise osv.except_osv(_('Account code too long'), _( - """Account code '%s' is too long to be exported to""" - """ EBP.""") % account_nb) - if len(move.name) > 15: - raise osv.except_osv(_('Move name too long'), _( - """Move name '%s' is too long to be exported to""" - """ EBP.""") % move.name) - - # Collect data for the file of move lines - if account_nb not in moves_data.keys(): - ref = ( - (line.company_id.ebp_trigram + ' ') - if line.company_id.ebp_trigram else '') - if move.partner_id.intercompany_trade: - ref += ' (' + move.partner_id.name + ')' - else: - ref += ( - line.name + - ((' (' + move.ref + ')') - if move.ref else '')) - moves_data[account_nb] = { - 'date': move.date, - 'journal': move.journal_id.ebp_code, - 'ref': normalize(ref), - 'name': normalize(move.name), - 'credit': line.credit, - 'debit': line.debit, - 'date_maturity': line.date_maturity, - } - if is_analytic_column: - moves_data[account_nb]['analytic'] =\ - line.company_id.ebp_trigram - else: - moves_data[account_nb]['credit'] += line.credit - moves_data[account_nb]['debit'] += line.debit - # Keep the earliest maturity date - if (line.date_maturity < - moves_data[account_nb]['date_maturity']): - moves_data[account_nb]['date_maturity'] =\ - line.date_maturity - - # Collect data for the file of accounts - # We can't just keep the account_id object because the data - # we want to export may be partner specific - if account_nb not in accounts_data.keys(): - if (data['form']['partner_accounts'] and - line.partner_id and line.partner_id.ebp_suffix and - line.account_id.type in ('payable', 'receivable')): - # Partner account - # Get the default address - if line.account_id.\ - is_intercompany_trade_fiscal_company: - partner = line.company_id.partner_id - else: - partner = line.partner_id - accounts_data[account_nb] = { - 'name': normalize(partner.name), - 'partner_name': normalize(partner.name), - 'address': normalize( - (partner.street or '') + - (partner.street2 and - (' ' + partner.street2) or '')), - 'zip': partner.zip or '', - 'city': normalize(partner.city or ''), - 'country': normalize( - partner.country_id.name or ''), - 'contact': normalize(partner.email or ''), - 'phone': partner.phone or partner.mobile or '', - 'fax': partner.fax or '', - } - elif (tax_code_suffix and - line.account_id.ebp_export_tax_code and - line.tax_code_id.ebp_suffix): - accounts_data[account_nb] = { - 'name': ( - normalize(line.account_id.name) + - '(' + normalize(line.tax_code_id.name) + ')'), - 'partner_name': '', - 'address': '', - 'zip': '', - 'city': '', - 'country': '', - 'contact': '', - 'phone': '', - 'fax': '', - } - else: - # Normal account - accounts_data[account_nb] = { - 'name': normalize(line.account_id.name), - 'partner_name': '', - 'address': '', - 'zip': '', - 'city': '', - 'country': '', - 'contact': '', - 'phone': '', - 'fax': '', - } - - accounts_data[account_nb].setdefault('credit', 0) - accounts_data[account_nb]['credit'] += line.credit - accounts_data[account_nb].setdefault('debit', 0) - accounts_data[account_nb]['debit'] += line.debit - - # Write the move summary to the file - _logger.debug("Writing the move summary to the file") - for account_nb, line in moves_data.iteritems(): - l += 1 - # TODO SLG : refactorer le if / else - if line['credit']: - move_line = ','.join([ - # Line number - '%d' % l, - # Date (ddmmyy) - '%s/%s/%s' % ( - line['date'][8:10], line['date'][5:7], - line['date'][2:4]), - # Journal - line['journal'].replace(',', '')[:4], - # Account number - # (possibly with the partner code appended to it) - account_nb.replace(',', ''), - # Manual title - '"%s"' % line['ref'][:40], - # Accountable receipt number - '"%s"' % line['name'][:15], - # Amount - '%f' % abs(line['credit']), - # [C]redit or [D]ebit - 'C', - # Date of maturity (ddmmyy) - line['date_maturity'] and '%s%s%s' % ( - line['date_maturity'][8:10], - line['date_maturity'][5:7], - line['date_maturity'][2:4]) or '', - # Currency - fiscalyear.company_id.currency_id.name.replace( - ',', ''), - ]) - if is_analytic_column: - move_line += ',' + line['analytic'] - moves_file.write(unidecode(move_line)) - moves_file.write('\r\n') - if line['debit']: - move_line = ','.join([ - # Line number - '%d' % l, - # Date (ddmmyy) - '%s/%s/%s' % ( - line['date'][8:10], line['date'][5:7], - line['date'][2:4]), - # Journal - line['journal'].replace(',', '')[:4], - # Account number - # (possibly with the partner code appended to it) - account_nb.replace(',', ''), - # Manual title - '"%s"' % line['ref'][:40], - # Accountable receipt number - '"%s"' % line['name'][:15], - # Amount - '%f' % abs(line['debit']), - # [C]redit or [D]ebit - 'D', - # Date of maturity (ddmmyy) - line['date_maturity'] and '%s%s%s' % ( - line['date_maturity'][8:10], - line['date_maturity'][5:7], - line['date_maturity'][2:4]) or '', - # Currency - fiscalyear.company_id.currency_id.name.replace( - ',', ''), - ]) - if is_analytic_column: - move_line += ',' + line['analytic'] - moves_file.write(unidecode(move_line)) - moves_file.write('\r\n') - exported_move_ids.append(move.id) - - # Mark the moves as exported to EBP - export_id = False - if len(exported_move_ids): - export_id = export_obj.create(cr, uid, { - 'fiscalyear_id': fiscalyear.id, - 'company_id': user_company.id, - 'description': data['form']['description'], - }, context=context) - self.pool.get('account.move').write(cr, uid, exported_move_ids, { - 'ebp_export_id': export_id, - }, context=context) - - # Header for Balance File - line2 = ','.join([ - "Account number", - "Account name", - "Debit", - "Credit", - "Debit Balance", - "Credit Balance", - ]) - balance_file.write(unidecode(line2)) - balance_file.write('\r\n') - - # Write the accounts into the file - # Write the balance of accounts into the file - for account_nb, account in accounts_data.iteritems(): - line = ','.join([ - account_nb.replace(',', ''), - (account['name'] or '').replace(',', '')[:60], - (account['partner_name'] or '').replace(',', '')[:30], - (account['address'] or '').replace(',', '')[:100], - (account['zip'] or '').replace(',', '')[:5], - (account['city'] or '').replace(',', '')[:30], - (account['country'] or '').replace(',', '')[:35], - (account['contact'] or '').replace(',', '')[:35], - (account['phone'] or '').replace(',', '')[:20], - (account['fax'] or '').replace(',', '')[:20], - ]) - account_file.write(unidecode(line)) - account_file.write('\r\n') - - credit = (account['credit'] or 0) - debit = (account['debit'] or 0) - if credit > debit: - credit_balance = credit - debit - debit_balance = 0 - else: - credit_balance = 0 - debit_balance = debit - credit - - line2 = ','.join([ - account_nb.replace(',', ''), - (account['name'] or '').replace(',', '')[:60], - str(debit), - str(credit), - str(debit_balance), - str(credit_balance), - ]) - balance_file.write(unidecode(line2)) - balance_file.write('\r\n') - - _logger.debug( - "%d accounts(s) exported to COMPTES.TXT" % len(accounts_data)) - - self.write(cr, uid, ids, { - 'exported_moves': len(exported_move_ids), - 'ignored_moves': len(ignored_move_ids), - 'exported_lines': l, - 'exported_accounts': len(accounts_data), - }, context=context) - if export_id: - export_obj.write(cr, uid, export_id, { - 'exported_moves': len(exported_move_ids), - 'ignored_moves': len(ignored_move_ids), - 'exported_lines': l, - 'exported_accounts': len(accounts_data), - }, context=context) - return export_id diff --git a/account_export_ebp/wizard/wizard_ebp_export.py b/account_export_ebp/wizard/wizard_ebp_export.py new file mode 100644 index 0000000..0d75d1e --- /dev/null +++ b/account_export_ebp/wizard/wizard_ebp_export.py @@ -0,0 +1,632 @@ +# coding: utf-8 +# Copyright (C) 2010 - 2015: Numérigraphe SARL +# Copyright (C) 2015 - Today: GRAP (http://www.grap.coop) +# @author: Julien WESTE +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +# import base64 +# import cStringIO +import logging + +from openerp import api, fields, models +# from openerp.exceptions import Warning as UserError + +_logger = logging.getLogger(__name__) + +# try: +# from unidecode import unidecode +# except ImportError: +# _logger.debug("account_export_ebp - 'unidecode' librairy not found") + + +class WizardEbpExport(models.TransientModel): + _name = "wizard.ebp.export" + + # Columns Section + ebp_export_id = fields.Many2one( + string='EBP Export', comodel_name='ebp.export', readonly=True) + + file_name_moves = fields.Char( + related='ebp_export_id.file_name_moves', readonly=True) + + file_name_accounts = fields.Char( + related='ebp_export_id.file_name_accounts', readonly=True) + + file_name_balance = fields.Char( + related='ebp_export_id.file_name_balance', readonly=True) + + data_moves = fields.Binary( + related='ebp_export_id.data_moves', readonly=True) + + data_accounts = fields.Binary( + related='ebp_export_id.data_accounts', readonly=True) + + data_balance = fields.Binary( + related='ebp_export_id.data_balance', readonly=True) + + fiscalyear_id = fields.Many2one( + comodel_name='account.fiscalyear', string='Fiscal year', + required=True, default=lambda s: s._default_fiscalyear_id(), + help='Only the moves in this fiscal will be exported') + + # Default Section + @api.model + def _default_fiscalyear_id(self): + AccountMove = self.env['account.move'] + moves = AccountMove.browse(self.env.context.get('active_ids', [])) + return self.env.context.get('active_id', False) + + # 'company_suffix': fields.boolean( + # 'Append company\'s code to accounts', + # help="""When this is checked, the company's code will be""" + # """ appended to the receivable and payable accounts' numbers in""" + # """ the exported files on every move line."""), + # 'partner_accounts': fields.boolean( + # 'Append partners\' code to accounts', + # help="""When this is checked, the partner's special code will""" + # """ be appended to the receivable and payable accounts' numbers""" + # """ in the exported files on every move line where a partner has""" + # """ been specified."""), + # 'tax_code_suffix': fields.boolean( + # 'Export according to Tax Codes', + # help="""Append Tax Code's suffix to account if the option is""" + # """ checked in the account"""), + # 'ignore_unchecked': fields.boolean( + # 'Ignore unchecked moves', + # help="""Please be aware that unchecked moves belong maybe some""" + # """ errors."""), + # 'ignore_draft': fields.boolean( + # 'Ignore draft moves', + # help="""Please be aware that draft moves do not not have a""" + # """ move number attached to them. As a consequence, they might""" + # """ not be imported correctly into EBP accounting software"""), + # 'ignore_exported': fields.boolean( + # 'Ignore moves already exported', + # help="Check this box unless you want to re-export moves to EBP"), + + # 'exported_moves': fields.integer( + # 'Number of moves exported', readonly=True), + # 'ignored_moves': fields.integer( + # 'Number of moves ignored', readonly=True), + # 'exported_lines': fields.integer( + # 'Number of lines exported', readonly=True), + # 'exported_accounts': fields.integer( + # 'Number of accounts exported', readonly=True), + # 'state': fields.selection([ + # ('export_ebp', 'Prepare Export'), + # ('export_ebp_end', 'Export Done'), + # ('export_ebp_download', 'Ready to download') + # ]), + # 'empty_suffixes_partner': fields.boolean( + # 'Empty Suffixes Partners', readonly=True), + # 'empty_suffixes_tax': fields.boolean( + # 'Empty Suffixes Taxes', readonly=True), + # 'description': fields.text( + # 'Description', help="Extra Description for Accountant Manager."), + + + + # # Defaults Section + # def _get_empty_suffixes_partner(self, cr, uid, context=None): + # rp_obj = self.pool.get('res.partner') + # aml_obj = self.pool.get('account.move.line') + + # rp_ids = rp_obj.search( + # cr, uid, [('ebp_suffix', '=', False)], context=context) + # aml_ids = aml_obj.search(cr, uid, [ + # ('date', '>=', '01/12/2012'), ('partner_id', 'in', rp_ids)], + # context=context) + + # if aml_ids: + # return True + # return False + + # def _get_empty_suffixes_tax(self, cr, uid, context=None): + # atc_obj = self.pool.get('account.tax.code') + # aml_obj = self.pool.get('account.move.line') + + # atc_ids = atc_obj.search( + # cr, uid, [('ebp_suffix', '=', False)], context=context) + # aml_ids = aml_obj.search(cr, uid, [ + # ('date', '>=', '01/12/2012'), ('tax_code_id', 'in', atc_ids)], + # context=context) + + # if aml_ids: + # return True + # return False + + # _defaults = { + # 'ignore_unchecked': lambda * a: True, + # 'ignore_exported': lambda * a: True, + # 'ignore_draft': lambda * a: True, + # 'company_suffix': lambda * a: True, + # 'partner_accounts': lambda * a: True, + # 'tax_code_suffix': lambda * a: True, + # 'state': 'export_ebp', + # 'empty_suffixes_partner': _get_empty_suffixes_partner, + # 'empty_suffixes_tax': _get_empty_suffixes_tax, + # } + + # def export(self, cr, uid, ids, context=None): + # if context is None: + # context = {} + # return self._download(cr, uid, ids, context=context) + + # def _download(self, cr, uid, ids, context=None): + # export_obj = self.pool.get('ebp.export') + # if context is None: + # context = {} + # this = self.browse(cr, uid, ids)[0] + # moves_file = cStringIO.StringIO() + # account_file = cStringIO.StringIO() + # balance_file = cStringIO.StringIO() + # export_id = self._export( + # cr, uid, ids, moves_file, account_file, balance_file, + # context=context) + + # out_moves = base64.encodestring(moves_file.getvalue()) + # out_accounts = base64.encodestring(account_file.getvalue()) + # out_balance = base64.encodestring(balance_file.getvalue()) + # moves_file.close() + # account_file.close() + # balance_file.close() + # self.write(cr, uid, ids, { + # 'state': 'export_ebp_download', + # 'data_moves': out_moves, + # 'data_accounts': out_accounts, + # 'data_balance': out_balance, + # 'name_moves': this.name_moves, + # 'name_accounts': this.name_accounts, + # 'name_balance': this.name_balance, + # }, context=context) + # export_obj.write(cr, uid, export_id, { + # 'data_accounts': out_accounts, + # 'data_balance': out_balance, + # 'data_moves': out_moves, + # }, context=context) + # return { + # 'type': 'ir.actions.act_window', + # 'res_model': 'account.export.ebp', + # 'view_mode': 'form', + # 'view_type': 'form', + # 'res_id': this.id, + # 'views': [(False, 'form')], + # 'target': 'new', + # } + + # def _export( + # self, cr, uid, ids, moves_file, account_file, balance_file, + # context=None): + # """ + # Export moves files usable by accounting software by EBP version + # 3 and above. + + # 2 files will be produced : + # - a file of accounting moves (ECRITURES.TXT) + # - a file of accounts (COMPTES.TXT) + # If stored in the right folder, these files will automatically be + # imported next time you open the folder in EBP. + + # Lines with an amount of 0 are not ignored even though EBP complains + # about them. This is to raise the attention of the person importing + # them into EBP. Also, journals with a code which does not meet EBP's + # requirements are not ignored. + + # Returns a dictionary containing the number of moves and lines + # exported and the number of moves ignored. + # """ + + # def normalize(text): + # # Remove tricky characters from the string + # if "\n;" in text: + # text = text.replace("\n;", " ") + # if ";" in text: + # text = text.replace(";", " ") + # if "," in text: + # text = text.replace(",", " ") + # if "\"" in text: + # text = text.replace("\"", " ") + # return text + + # if context is None: + # context = {} + # export_obj = self.pool.get('ebp.export') + + # data = {'form': self.read(cr, uid, ids, context=context)[0]} + # _logger.debug("Form data: %s" % data['form']) + + # # Read the EBP year number name from the selected fiscal year + # fiscalyear = self.pool.get('account.fiscalyear').browse( + # cr, uid, data['form']['fiscalyear_id'][0], context) + # user_company = self.pool.get('res.users').browse( + # cr, uid, uid, context=context).company_id + + # # Sanity checks + # if context.get('active_model', '') != 'account.move': + # raise osv.except_osv( + # _('Wrong Object'), + # _("This wizard should only be used on accounting moves")) + + # # dictionary to store accounts while we loop through move lines + # accounts_data = {} + # # Line counter + # l = 0 + # moves = self.pool.get('account.move').browse( + # cr, uid, context.get('active_ids', []), context=context) + + # is_analytic_column = False + # for move in moves: + # if move.company_id.ebp_trigram != '': + # is_analytic_column = True + + # # The move summaries will be written to a CSV file encoded in + # # win-latin-1 + # # TODO we should report errors more cleanly to the users here + + # tax_code_suffix = data['form']['tax_code_suffix'] + # exported_move_ids = [] + # ignored_move_ids = [] + + # # Move File header + # move_line = ','.join([ + # "Ligne", + # "Date", + # "Code journal", + # "N° de compte", + # "Intitulé", + # "Pièce", + # "Montant (associé au sens)", + # "Sens", + # "Échéance", + # "Monnaie", + # ]) + # if is_analytic_column: + # move_line += ',Poste analytique' + + # moves_file.write(move_line) + # moves_file.write('\r\n') + + # for move in moves: + # # Ignore draft moves unless the user asked for them + # ignore_draft = ( + # data['form']['ignore_draft'] and move.state == 'draft') + # ignore_unchecked = ( + # data['form']['ignore_unchecked'] and move.to_check) + # # Ignore moves in other fiscal years + # ignore_year = (move.period_id.fiscalyear_id.id != + # data['form']['fiscalyear_id'][0]) + # # Ignore moves already exported + # ignore_exported = ( + # data['form']['ignore_exported'] and move.ebp_export_id) + # # Skip to next move if this one should be ignored + # if ignore_draft or ignore_year or\ + # ignore_exported or ignore_unchecked: + # _logger.debug( + # """Ignoring move %d - draft: %s, wrong year: %s,""" + # """ exported: %s""" % ( + # move.id, ignore_draft, ignore_year, ignore_exported)) + # ignored_move_ids.append(move.id) + # continue + + # _logger.debug("Exporting move %d" % move.id) + # # dictionary to summarize the lines of the move by account + # moves_data = {} + # for line in move.line_id: + # _logger.debug("Examining move line %d" % line.id) + + # if line.credit == line.debit: + # _logger.debug( + # """Move line %d has a sum equal to zero and will""" + # """ not be exported.""" % line.id) + # continue + # # Make up the account number + # account_nb = normalize(line.account_id.code) + # if data['form']['company_suffix'] and line.company_id and\ + # line.company_id.ebp_trigram and\ + # line.account_id.type in ('payable', 'receivable')\ + # and not line.account_id\ + # .is_intercompany_trade_fiscal_company: + # account_nb = account_nb + line.company_id.ebp_trigram + # if data['form']['partner_accounts'] and line.partner_id and\ + # line.partner_id.ebp_suffix and\ + # line.account_id.type in ('payable', 'receivable')\ + # and not line.account_id\ + # .is_intercompany_trade_fiscal_company: + # # Partner account + # account_nb = account_nb + line.partner_id.ebp_suffix + # if (tax_code_suffix and line.account_id.ebp_export_tax_code): + # if line.tax_code_id.ebp_suffix: + # account_nb = account_nb + line.tax_code_id.ebp_suffix + # else: + # if not line.account_id.ebp_code_no_tax: + # raise osv.except_osv( + # _('Incorrect Setting'), + # _("The account %s - %s is set 'export with tax" + # " suffix' but no tax suffix is defined for" + # " the account.\n Move %s" % ( + # line.account_id.code, + # line.account_id.name, + # line.move_id.name))) + # else: + # account_nb = account_nb +\ + # line.account_id.ebp_code_no_tax + + # # Check the most important fields are not above the maximum + # # length so as not to export wrong data with catastrophic + # # consequence + # if not move.journal_id.ebp_code or\ + # len(move.journal_id.ebp_code) == 0: + # raise osv.except_osv( + # _('Journal code Undefined'), + # _("Journal '%s' has no EBP Code defined." % + # move.journal_id.name)) + # if len(move.journal_id.ebp_code) > 4: + # raise osv.except_osv( + # _('Journal code too long'), + # _("Journal code '%s' is too long to be exported" + # " to EBP." % move.journal_id.ebp_code)) + + # # The docs from EBP state that account codes may be up to + # # 15 characters but "EBP Comptabilité" v13 will refuse anything + # # longer than 10 characters + # if len(account_nb) > 10: + # raise osv.except_osv(_('Account code too long'), _( + # """Account code '%s' is too long to be exported to""" + # """ EBP.""") % account_nb) + # if len(move.name) > 15: + # raise osv.except_osv(_('Move name too long'), _( + # """Move name '%s' is too long to be exported to""" + # """ EBP.""") % move.name) + + # # Collect data for the file of move lines + # if account_nb not in moves_data.keys(): + # ref = ( + # (line.company_id.ebp_trigram + ' ') + # if line.company_id.ebp_trigram else '') + # if move.partner_id.intercompany_trade: + # ref += ' (' + move.partner_id.name + ')' + # else: + # ref += ( + # line.name + + # ((' (' + move.ref + ')') + # if move.ref else '')) + # moves_data[account_nb] = { + # 'date': move.date, + # 'journal': move.journal_id.ebp_code, + # 'ref': normalize(ref), + # 'name': normalize(move.name), + # 'credit': line.credit, + # 'debit': line.debit, + # 'date_maturity': line.date_maturity, + # } + # if is_analytic_column: + # moves_data[account_nb]['analytic'] =\ + # line.company_id.ebp_trigram + # else: + # moves_data[account_nb]['credit'] += line.credit + # moves_data[account_nb]['debit'] += line.debit + # # Keep the earliest maturity date + # if (line.date_maturity < + # moves_data[account_nb]['date_maturity']): + # moves_data[account_nb]['date_maturity'] =\ + # line.date_maturity + + # # Collect data for the file of accounts + # # We can't just keep the account_id object because the data + # # we want to export may be partner specific + # if account_nb not in accounts_data.keys(): + # if (data['form']['partner_accounts'] and + # line.partner_id and line.partner_id.ebp_suffix and + # line.account_id.type in ('payable', 'receivable')): + # # Partner account + # # Get the default address + # if line.account_id.\ + # is_intercompany_trade_fiscal_company: + # partner = line.company_id.partner_id + # else: + # partner = line.partner_id + # accounts_data[account_nb] = { + # 'name': normalize(partner.name), + # 'partner_name': normalize(partner.name), + # 'address': normalize( + # (partner.street or '') + + # (partner.street2 and + # (' ' + partner.street2) or '')), + # 'zip': partner.zip or '', + # 'city': normalize(partner.city or ''), + # 'country': normalize( + # partner.country_id.name or ''), + # 'contact': normalize(partner.email or ''), + # 'phone': partner.phone or partner.mobile or '', + # 'fax': partner.fax or '', + # } + # elif (tax_code_suffix and + # line.account_id.ebp_export_tax_code and + # line.tax_code_id.ebp_suffix): + # accounts_data[account_nb] = { + # 'name': ( + # normalize(line.account_id.name) + + # '(' + normalize(line.tax_code_id.name) + ')'), + # 'partner_name': '', + # 'address': '', + # 'zip': '', + # 'city': '', + # 'country': '', + # 'contact': '', + # 'phone': '', + # 'fax': '', + # } + # else: + # # Normal account + # accounts_data[account_nb] = { + # 'name': normalize(line.account_id.name), + # 'partner_name': '', + # 'address': '', + # 'zip': '', + # 'city': '', + # 'country': '', + # 'contact': '', + # 'phone': '', + # 'fax': '', + # } + + # accounts_data[account_nb].setdefault('credit', 0) + # accounts_data[account_nb]['credit'] += line.credit + # accounts_data[account_nb].setdefault('debit', 0) + # accounts_data[account_nb]['debit'] += line.debit + + # # Write the move summary to the file + # _logger.debug("Writing the move summary to the file") + # for account_nb, line in moves_data.iteritems(): + # l += 1 + # # TODO SLG : refactorer le if / else + # if line['credit']: + # move_line = ','.join([ + # # Line number + # '%d' % l, + # # Date (ddmmyy) + # '%s/%s/%s' % ( + # line['date'][8:10], line['date'][5:7], + # line['date'][2:4]), + # # Journal + # line['journal'].replace(',', '')[:4], + # # Account number + # # (possibly with the partner code appended to it) + # account_nb.replace(',', ''), + # # Manual title + # '"%s"' % line['ref'][:40], + # # Accountable receipt number + # '"%s"' % line['name'][:15], + # # Amount + # '%f' % abs(line['credit']), + # # [C]redit or [D]ebit + # 'C', + # # Date of maturity (ddmmyy) + # line['date_maturity'] and '%s%s%s' % ( + # line['date_maturity'][8:10], + # line['date_maturity'][5:7], + # line['date_maturity'][2:4]) or '', + # # Currency + # fiscalyear.company_id.currency_id.name.replace( + # ',', ''), + # ]) + # if is_analytic_column: + # move_line += ',' + line['analytic'] + # moves_file.write(unidecode(move_line)) + # moves_file.write('\r\n') + # if line['debit']: + # move_line = ','.join([ + # # Line number + # '%d' % l, + # # Date (ddmmyy) + # '%s/%s/%s' % ( + # line['date'][8:10], line['date'][5:7], + # line['date'][2:4]), + # # Journal + # line['journal'].replace(',', '')[:4], + # # Account number + # # (possibly with the partner code appended to it) + # account_nb.replace(',', ''), + # # Manual title + # '"%s"' % line['ref'][:40], + # # Accountable receipt number + # '"%s"' % line['name'][:15], + # # Amount + # '%f' % abs(line['debit']), + # # [C]redit or [D]ebit + # 'D', + # # Date of maturity (ddmmyy) + # line['date_maturity'] and '%s%s%s' % ( + # line['date_maturity'][8:10], + # line['date_maturity'][5:7], + # line['date_maturity'][2:4]) or '', + # # Currency + # fiscalyear.company_id.currency_id.name.replace( + # ',', ''), + # ]) + # if is_analytic_column: + # move_line += ',' + line['analytic'] + # moves_file.write(unidecode(move_line)) + # moves_file.write('\r\n') + # exported_move_ids.append(move.id) + + # # Mark the moves as exported to EBP + # export_id = False + # if len(exported_move_ids): + # export_id = export_obj.create(cr, uid, { + # 'fiscalyear_id': fiscalyear.id, + # 'company_id': user_company.id, + # 'description': data['form']['description'], + # }, context=context) + # self.pool.get('account.move').write(cr, uid, exported_move_ids, { + # 'ebp_export_id': export_id, + # }, context=context) + + # # Header for Balance File + # line2 = ','.join([ + # "Account number", + # "Account name", + # "Debit", + # "Credit", + # "Debit Balance", + # "Credit Balance", + # ]) + # balance_file.write(unidecode(line2)) + # balance_file.write('\r\n') + + # # Write the accounts into the file + # # Write the balance of accounts into the file + # for account_nb, account in accounts_data.iteritems(): + # line = ','.join([ + # account_nb.replace(',', ''), + # (account['name'] or '').replace(',', '')[:60], + # (account['partner_name'] or '').replace(',', '')[:30], + # (account['address'] or '').replace(',', '')[:100], + # (account['zip'] or '').replace(',', '')[:5], + # (account['city'] or '').replace(',', '')[:30], + # (account['country'] or '').replace(',', '')[:35], + # (account['contact'] or '').replace(',', '')[:35], + # (account['phone'] or '').replace(',', '')[:20], + # (account['fax'] or '').replace(',', '')[:20], + # ]) + # account_file.write(unidecode(line)) + # account_file.write('\r\n') + + # credit = (account['credit'] or 0) + # debit = (account['debit'] or 0) + # if credit > debit: + # credit_balance = credit - debit + # debit_balance = 0 + # else: + # credit_balance = 0 + # debit_balance = debit - credit + + # line2 = ','.join([ + # account_nb.replace(',', ''), + # (account['name'] or '').replace(',', '')[:60], + # str(debit), + # str(credit), + # str(debit_balance), + # str(credit_balance), + # ]) + # balance_file.write(unidecode(line2)) + # balance_file.write('\r\n') + + # _logger.debug( + # "%d accounts(s) exported to COMPTES.TXT" % len(accounts_data)) + + # self.write(cr, uid, ids, { + # 'exported_moves': len(exported_move_ids), + # 'ignored_moves': len(ignored_move_ids), + # 'exported_lines': l, + # 'exported_accounts': len(accounts_data), + # }, context=context) + # if export_id: + # export_obj.write(cr, uid, export_id, { + # 'exported_moves': len(exported_move_ids), + # 'ignored_moves': len(ignored_move_ids), + # 'exported_lines': l, + # 'exported_accounts': len(accounts_data), + # }, context=context) + # return export_id diff --git a/account_export_ebp/wizard/wizard_ebp_unexport.py b/account_export_ebp/wizard/wizard_ebp_unexport.py new file mode 100644 index 0000000..d2e5820 --- /dev/null +++ b/account_export_ebp/wizard/wizard_ebp_unexport.py @@ -0,0 +1,20 @@ +# coding: utf-8 +# Copyright (C) 2010 - 2015: Numérigraphe SARL +# Copyright (C) 2015 - Today: GRAP (http://www.grap.coop) +# @author: Julien WESTE +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from openerp import _, api, fields, models +from openerp.exceptions import Warning as UserError + + +class WizardEbpUnexport(models.TransientModel): + _name = 'wizard.ebp.unexport' + + @api.multi + def button_unexport(self): + AccountMove = self.env['account.move'] + moves = AccountMove.browse(self.env.context.get('active_ids', False)) + moves.write({'ebp_export_id': False}) diff --git a/account_export_ebp/wizard/wizard_add_suffix.py b/account_export_ebp/wizard/wizard_res_partner_add_suffix.py similarity index 98% rename from account_export_ebp/wizard/wizard_add_suffix.py rename to account_export_ebp/wizard/wizard_res_partner_add_suffix.py index 024df9b..aa054c4 100644 --- a/account_export_ebp/wizard/wizard_add_suffix.py +++ b/account_export_ebp/wizard/wizard_res_partner_add_suffix.py @@ -19,8 +19,8 @@ logger.debug("account_export_ebp - 'unidecode' librairy not found") -class account_add_suffix(TransientModel): - _name = "account.add.suffix" +class WizardResPartnerAddSuffix(TransientModel): + _name = "wizard.res.partner.add.suffix" _columns = { 'line_ids': fields.one2many( diff --git a/account_export_ebp/wizard/wizard_res_partner_add_suffix.xml b/account_export_ebp/wizard/wizard_res_partner_add_suffix.xml new file mode 100644 index 0000000..b0fcdd8 --- /dev/null +++ b/account_export_ebp/wizard/wizard_res_partner_add_suffix.xml @@ -0,0 +1,36 @@ + + + + + + wizard.res.partner.add.suffix + + +
+
+ + + + + + + + +
+
+ + + Add EBP Suffixes + ir.actions.act_window + wizard.res.partner.add.suffix + form + form + new + + +
diff --git a/account_export_ebp/wizard/wizard_unexport.py b/account_export_ebp/wizard/wizard_unexport.py deleted file mode 100644 index 0db237e..0000000 --- a/account_export_ebp/wizard/wizard_unexport.py +++ /dev/null @@ -1,29 +0,0 @@ -# coding: utf-8 -# Copyright (C) 2010 - 2015: Numérigraphe SARL -# Copyright (C) 2015 - Today: GRAP (http://www.grap.coop) -# @author: Julien WESTE -# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from openerp.osv import osv -import logging -_logger = logging.getLogger(__name__) - - -class account_unexport_ebp(osv.TransientModel): - _name = "account.unexport.ebp" - - # Columns Section - _columns = { - } - - def unexport(self, cr, uid, ids, context=None): - if context is None: - context = {} - unexport_ids = context.get('active_ids', False) - am_obj = self.pool.get('account.move') - am_obj.write(cr, uid, unexport_ids, { - 'ebp_export_id': False, - }, context=context) - # TODO: find the file in ebp.export model and remove the move lines - return ids From f95d07ca56a11538d4a83a52b5e853df85ca1985 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Fri, 12 Oct 2018 17:07:13 +0200 Subject: [PATCH 03/11] [WIP] --- account_export_ebp/models/ebp_export.py | 4 +-- .../views/view_account_tax_code.xml | 23 ++++-------- account_export_ebp/views/view_ebp_export.xml | 6 ++-- account_export_ebp/views/view_res_partner.xml | 2 +- .../wizard/view_wizard_ebp_export.xml | 9 +++-- .../view_wizard_res_partner_add_suffix.xml | 2 +- .../wizard/wizard_res_partner_add_suffix.xml | 36 ------------------- 7 files changed, 17 insertions(+), 65 deletions(-) delete mode 100644 account_export_ebp/wizard/wizard_res_partner_add_suffix.xml diff --git a/account_export_ebp/models/ebp_export.py b/account_export_ebp/models/ebp_export.py index 270d125..a207822 100644 --- a/account_export_ebp/models/ebp_export.py +++ b/account_export_ebp/models/ebp_export.py @@ -32,8 +32,8 @@ class EbpExport(models.Model): help="Extra Description for Accountant Manager.") exported_move_qty = fields.Integer( - oldname='exported_moves' - 'Quantity of Moves Exported', readonly=True) + oldname='exported_moves', + string='Quantity of Moves Exported', readonly=True) exported_account_qty = fields.Integer( oldname='exported_accounts', diff --git a/account_export_ebp/views/view_account_tax_code.xml b/account_export_ebp/views/view_account_tax_code.xml index 8e926e1..d2d74be 100644 --- a/account_export_ebp/views/view_account_tax_code.xml +++ b/account_export_ebp/views/view_account_tax_code.xml @@ -14,7 +14,6 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). name="no_suffix" domain="[('ebp_suffix', '=', False)]" groups="account.group_account_manager"/> - - account.tax.code - - - - - - - - - account.tax.code @@ -56,20 +45,20 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + Tax Code Suffix View ir.actions.act_window account.tax.code form tree - + {'search_default_with_moves': 1, 'search_default_no_suffix': 1} - diff --git a/account_export_ebp/views/view_ebp_export.xml b/account_export_ebp/views/view_ebp_export.xml index 434a4f6..55307c0 100644 --- a/account_export_ebp/views/view_ebp_export.xml +++ b/account_export_ebp/views/view_ebp_export.xml @@ -51,9 +51,9 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -

Here is the exported moves file:

-

And the exported accounts file:

-

And the exported balance file:

+

Here is the exported moves file:

+

And the exported accounts file:

+

And the exported balance file:

diff --git a/account_export_ebp/views/view_res_partner.xml b/account_export_ebp/views/view_res_partner.xml index 259f633..b8be760 100644 --- a/account_export_ebp/views/view_res_partner.xml +++ b/account_export_ebp/views/view_res_partner.xml @@ -56,7 +56,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). res.partner form tree - + {'search_default_with_moves': 1,'search_default_no_suffix': 1}
diff --git a/account_export_ebp/wizard/view_wizard_ebp_export.xml b/account_export_ebp/wizard/view_wizard_ebp_export.xml index 03588f6..f8707ff 100644 --- a/account_export_ebp/wizard/view_wizard_ebp_export.xml +++ b/account_export_ebp/wizard/view_wizard_ebp_export.xml @@ -6,8 +6,8 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). --> - - account.export.ebp + + wizard.ebp.export
@@ -61,13 +61,12 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + Export to EBP ir.actions.act_window - account.export.ebp + wizard.ebp.export form form - new diff --git a/account_export_ebp/wizard/view_wizard_res_partner_add_suffix.xml b/account_export_ebp/wizard/view_wizard_res_partner_add_suffix.xml index fd9695d..b0fcdd8 100644 --- a/account_export_ebp/wizard/view_wizard_res_partner_add_suffix.xml +++ b/account_export_ebp/wizard/view_wizard_res_partner_add_suffix.xml @@ -24,7 +24,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + Add EBP Suffixes ir.actions.act_window wizard.res.partner.add.suffix diff --git a/account_export_ebp/wizard/wizard_res_partner_add_suffix.xml b/account_export_ebp/wizard/wizard_res_partner_add_suffix.xml deleted file mode 100644 index b0fcdd8..0000000 --- a/account_export_ebp/wizard/wizard_res_partner_add_suffix.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - wizard.res.partner.add.suffix - - -
-
- - - - - - - - -
-
- - - Add EBP Suffixes - ir.actions.act_window - wizard.res.partner.add.suffix - form - form - new - - -
From f97beaef1bbfc1488612706740d0071f8ed44310 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 15 Oct 2018 11:24:52 +0200 Subject: [PATCH 04/11] [WIP] --- account_export_ebp/__openerp__.py | 2 +- account_export_ebp/models/ebp_export.py | 399 +++++++++++++++++- .../views/view_account_move.xml | 4 +- .../wizard/view_wizard_ebp_export.xml | 36 +- .../wizard/wizard_ebp_export.py | 80 +++- 5 files changed, 486 insertions(+), 35 deletions(-) diff --git a/account_export_ebp/__openerp__.py b/account_export_ebp/__openerp__.py index fcc1d15..c111c9e 100644 --- a/account_export_ebp/__openerp__.py +++ b/account_export_ebp/__openerp__.py @@ -50,8 +50,8 @@ 'security/ir_rule.xml', 'views/menu.xml', 'wizard/view_wizard_res_partner_add_suffix.xml', + 'wizard/view_wizard_ebp_export.xml', 'wizard/view_wizard_ebp_unexport.xml', - # 'wizard/view_wizard_ebp_export.xml', 'views/view_account_account.xml', 'views/view_account_journal.xml', 'views/view_account_move.xml', diff --git a/account_export_ebp/models/ebp_export.py b/account_export_ebp/models/ebp_export.py index a207822..ad562c6 100644 --- a/account_export_ebp/models/ebp_export.py +++ b/account_export_ebp/models/ebp_export.py @@ -6,16 +6,19 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from openerp import _, api, fields, models +from openerp.Exceptions import Warning as UserError class EbpExport(models.Model): _name = 'ebp.export' _order = 'date desc' + _EBP_REMOVE_CHAR_LIST = ['\n;', ';', ',', '"'] + # Column Section company_id = fields.Many2one( comodel_name='res.company', string='Company', required=True, - readonly=True) + readonly=True, default=lambda s: s._default_company_id()) fiscalyear_id = fields.Many2one( comodel_name='account.fiscalyear', string='Fiscal year', required=True, @@ -61,6 +64,11 @@ class EbpExport(models.Model): file_name_balance = fields.Char( readonly=True, compute='_compute_file_name_balance') + # Default Section + @api.model + def _default_company_id(self): + return self.env.user.company_id.id + # Compute Section @api.multi def _compute_name(self): @@ -84,3 +92,392 @@ def _compute_file_name_balance(self): for export in self: export.file_name_balance =\ 'export_%d_%s.csv' % (export.id, _("BALANCE")) + + # Custom Section + @api.model + def _ebp_normalize(self, text): + res = text + for char in self._EBP_REMOVE_CHAR_LIST: + res = res.replace(char, " ") + return res + + @api.multi + def export(self, moves): + """Export moves into 3 files and mark th moves as exported""" + self.ensure_one() + # Create files + moves_file = cStringIO.StringIO() + accounts_file = cStringIO.StringIO() + balance_file = cStringIO.StringIO() + + # Export into files + self._write_header_into_moves_file(moves_file) + self._write_header_into_balance_file(balance_file) + + self._export_to_files(moves, move_file, account_file, balance_file) + data_moves = base64.encodestring(moves_file.getvalue()) + data_accounts = base64.encodestring(account_file.getvalue()) + data_balance = base64.encodestring(balance_file.getvalue()) + moves_file.close() + account_file.close() + balance_file.close() + + # Save Datas + self.write({ + 'data_moves': data_moves, + 'data_accounts': data_accounts, + 'data_balance': data_balance, + }) + + # Mark moves as exported + moves.write({ + 'ebp_export_id': self.id, + }) + + @api.model + def _export_to_files(self, moves, move_file, account_file, balance_file): + # dictionary to store accounts while we loop through move lines + accounts_data = {} + # Line counter + i = 0 + + for move in moves: + # dictionary to summarize the lines of the move by account + moves_data = {} + for line in move.line_id: + if line.credit == line.debit: + # Ignoring line with null debit and credit + continue + + account_code = self._get_account_code(move, line) + + # Collect data for the file of move lines + if account_code not in moves_data.keys(): + moves_data[account_code] = self._prepare_move_line_dict( + move, line) + else: + moves_data[account_code]['credit'] += line.credit + moves_data[account_code]['debit'] += line.debit + # Keep the earliest maturity date + if (line.date_maturity < + moves_data[account_code]['date_maturity']): + moves_data[account_code]['date_maturity'] =\ + line.date_maturity + + # Collect data for the file of accounts + if account_code not in accounts_data.keys(): + accounts_data[account_code] = self._prepare_account_dict( + move, line) + accounts_data[account_code]['credit'] += line.credit + accounts_data[account_code]['debit'] += line.debit + + # Write to file + self._write_into_moves_file(i, moves_data, moves_file) + i += len(moves_data) + + + # Write the accounts into the file + self._write_into_accounts_file(i, accounts_data, accounts_file) + + + # # Write the balance of accounts into the file + self._write_into_balance_file(i, accounts_data, balance_file) + + @api.model + def _write_header_into_moves_file(self, moves_file): + # Move File header + data = [ + "Ligne", + "Date", + "Code journal", + "N° de compte", + "Intitulé", + "Pièce", + "Montant (associé au sens)", + "Sens", + "Échéance", + "Monnaie", + ] + self._write_into_file(data, moves_file) + + @api.model + def _write_header_into_balance_file(self, balance_file): + # Move File header + data = [ + "Account number", + "Account name", + "Debit", + "Credit", + "Debit Balance", + "Credit Balance", + ] + self._write_into_file(data, balance_file) + + @api.model + def _get_account_code(self, move, line): + account = line.account_id + company = line.company_id + partner = line.partner_id + res = account.code + # TODO CHECK Camille E + company_suffix = True + partner_accounts = True + tax_code_suffix = True + + # Company Suffix + if company_suffix and company.ebp_trigram\ + and account.type in ('payable', 'receivable')\ + and not account.is_intercompany_trade_fiscal_company: + res += company.ebp_trigram + + # Partner Suffix + if partner_accounts and partner and partner.ebp_suffix\ + and account.type in ('payable', 'receivable')\ + and not account.is_intercompany_trade_fiscal_company: + res += partner.ebp_suffix + + # Tax Suffix + if tax_code_suffix and account.ebp_export_tax_code: + if line.tax_code_id.ebp_suffix: + # Tax code is defined + res += line.tax_code_id.ebp_suffix + else: + if not account.ebp_code_no_tax: + raise UserError(_( + "The account %s - %s is set 'export with tax" + " suffix' but no tax suffix is defined for" + " the account.\n Move %s" % ( + account.code, + account.name, + move.name))) + else: + res += account.ebp_code_no_tax + if len(res) > 10: + # The docs from EBP state that account codes may be up to + # 15 characters but "EBP Comptabilité" v13 will refuse anything + # longer than 10 characters + raise UserError(_( + "Account code '%s' is too long to be exported to" + " EBP.") % res) + return res + + @api.model + def _prepare_move_line_dict(self, move, line): + ref = ( + (line.company_id.ebp_trigram + ' ') + if line.company_id.ebp_trigram else '') + if move.partner_id.intercompany_trade: + ref += ' (' + move.partner_id.name + ')' + else: + ref += ( + line.name + + ((' (' + move.ref + ')') + if move.ref else '')) + return { + 'date': move.date, + 'journal': move.journal_id.ebp_code, + 'ref': self._normalize(ref), + 'name': self._normalize(move.name), + 'credit': line.credit, + 'debit': line.debit, + 'date_maturity': line.date_maturity, + 'currency_name': move.company_id.currency_id.name, + 'analytic': line.company_id.ebp_trigram, + } + + @api.model + def _write_into_moves_file(count, moves_data, moves_file): + i = count + + for account_code, line in moves_data.iteritems(): + i += 1 + # TODO SLG : refactorer le if / else + data = [ + # Line number + '%d' % i, + # Date (ddmmyy) + '%s/%s/%s' % ( + line['date'][8:10], line['date'][5:7], + line['date'][2:4]), + # Journal + line['journal'].replace(',', '')[:4], + # Account number + # (possibly with the partner code appended to it) + account_code.replace(',', ''), + # Manual title + '"%s"' % line['ref'][:40], + # Accountable receipt number + '"%s"' % line['name'][:15], + ] + if line['credit']: + data += [ + # Amount + '%f' % abs(line['credit']), + # [C]redit or [D]ebit + 'C', + ] + else: + data += [ + # Amount + '%f' % abs(line['debit']), + # [C]redit or [D]ebit + 'D', + ] + data += [ + # Date of maturity (ddmmyy) + line['date_maturity'] and '%s%s%s' % ( + line['date_maturity'][8:10], + line['date_maturity'][5:7], + line['date_maturity'][2:4]) or '', + # Currency + line['currency_name'], + ] + # TODO Check analytic + if True: + data += [ + line['analytic'], + ] + self._write_into_file(data, moves_file) + + @api.model + def _prepare_account_dict(self, move, line): + res = { + 'name': '', + 'partner_name': '', + 'address': '', + 'zip': '', + 'city': '', + 'country': '', + 'contact': '', + 'phone': '', + 'fax': '', + 'credit': 0, + 'debit': 0, + } + # TODO CHECK Camille E + partner_accounts = True + tax_code_suffix = True + + if (partner_accounts and + line.partner_id and line.partner_id.ebp_suffix and + line.account_id.type in ('payable', 'receivable')): + # Partner account + if line.account_id.\ + is_intercompany_trade_fiscal_company: + partner = line.company_id.partner_id + else: + partner = line.partner_id + res.update({ + 'name': self._normalize(partner.name), + 'partner_name': self._normalize(partner.name), + 'address': self._normalize( + (partner.street or '') + + (partner.street2 and + (' ' + partner.street2) or '')), + 'zip': partner.zip or '', + 'city': self._normalize(partner.city or ''), + 'country': self._normalize( + partner.country_id.name or ''), + 'contact': self._normalize(partner.email or ''), + 'phone': partner.phone or partner.mobile or '', + 'fax': partner.fax or '', + }) + elif (tax_code_suffix and + line.account_id.ebp_export_tax_code and + line.tax_code_id.ebp_suffix): + res.update({ + 'name': ( + self._normalize(line.account_id.name) + + '(' + self._normalize(line.tax_code_id.name) + ')'), + }) + else: + # Normal account + res.update({ + 'name': self._normalize(line.account_id.name), + }) + + @api.model + def _write_into_accounts_file(count, accounts_data, accounts_file): + for account_code, account_data in accounts_data.iteritems(): + data = [ + account_code.replace(',', ''), + (account_data['name'] or '').replace(',', '')[:60], + (account_data['partner_name'] or '').replace(',', '')[:30], + (account_data['address'] or '').replace(',', '')[:100], + (account_data['zip'] or '').replace(',', '')[:5], + (account_data['city'] or '').replace(',', '')[:30], + (account_data['country'] or '').replace(',', '')[:35], + (account_data['contact'] or '').replace(',', '')[:35], + (account_data['phone'] or '').replace(',', '')[:20], + (account_data['fax'] or '').replace(',', '')[:20], + ] + self._write_into_file(data, accounts_file) + + @api.model + def _write_into_balance_file(count, accounts_data, balance_file): + for account_code, account_data in accounts_data.iteritems(): + credit = (account['credit'] or 0) + debit = (account['debit'] or 0) + if credit > debit: + credit_balance = credit - debit + debit_balance = 0 + else: + credit_balance = 0 + debit_balance = debit - credit + data = [ + account_code.replace(',', ''), + (account['name'] or '').replace(',', '')[:60], + str(debit), + str(credit), + str(debit_balance), + str(credit_balance), + ] + self._write_into_file(data, balance_file) + + @api.model + def _write_into_file(self, data_list, file): + file.write(unidecode(','.join(data_list))) + file.write('\r\n') + + # _logger.debug( + # "%d accounts(s) exported to COMPTES.TXT" % len(accounts_data)) + + # self.write(cr, uid, ids, { + # 'exported_moves': len(exported_move_ids), + # 'ignored_moves': len(ignored_move_ids), + # 'exported_lines': l, + # 'exported_accounts': len(accounts_data), + # }, context=context) + # if export_id: + # export_obj.write(cr, uid, export_id, { + # 'exported_moves': len(exported_move_ids), + # 'ignored_moves': len(ignored_move_ids), + # 'exported_lines': l, + # 'exported_accounts': len(accounts_data), + # }, context=context) + # return export_id + + + + + + + +# FILE +# FUCK ANALYTIC + + # is_analytic_column = False + # for move in moves: + # if move.company_id.ebp_trigram != '': + # is_analytic_column = True + + # if is_analytic_column: + # move_line += ',Poste analytique' + + + + # AH BON ???? + # if len(move.name) > 15: + # raise osv.except_osv(_('Move name too long'), _( + # """Move name '%s' is too long to be exported to""" + # """ EBP.""") % move.name) diff --git a/account_export_ebp/views/view_account_move.xml b/account_export_ebp/views/view_account_move.xml index 3d80198..edf9cfe 100644 --- a/account_export_ebp/views/view_account_move.xml +++ b/account_export_ebp/views/view_account_move.xml @@ -37,7 +37,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
- + Cancel EBP Export diff --git a/account_export_ebp/wizard/view_wizard_ebp_export.xml b/account_export_ebp/wizard/view_wizard_ebp_export.xml index f8707ff..549f71b 100644 --- a/account_export_ebp/wizard/view_wizard_ebp_export.xml +++ b/account_export_ebp/wizard/view_wizard_ebp_export.xml @@ -10,8 +10,11 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). wizard.ebp.export
- - +
+ +
+ + + + - - - - - - - - +
-
- +
diff --git a/account_export_ebp/wizard/wizard_ebp_export.py b/account_export_ebp/wizard/wizard_ebp_export.py index 0d75d1e..f1986fa 100644 --- a/account_export_ebp/wizard/wizard_ebp_export.py +++ b/account_export_ebp/wizard/wizard_ebp_export.py @@ -23,10 +23,24 @@ class WizardEbpExport(models.TransientModel): _name = "wizard.ebp.export" + _STATE_SELECTION = [ + ('draft', 'Draft'), + ('done', 'Done'), + ] + # Columns Section ebp_export_id = fields.Many2one( string='EBP Export', comodel_name='ebp.export', readonly=True) + state = fields.Selection( + selection=_STATE_SELECTION, string='State', default='draft') + + fiscalyear_id = fields.Many2one( + comodel_name='account.fiscalyear', string='Fiscal year', + required=True, default=lambda s: s._default_fiscalyear_id(), + domain="[('state', '=', 'draft')]", + help='Only the moves in this fiscal will be exported') + file_name_moves = fields.Char( related='ebp_export_id.file_name_moves', readonly=True) @@ -45,17 +59,67 @@ class WizardEbpExport(models.TransientModel): data_balance = fields.Binary( related='ebp_export_id.data_balance', readonly=True) - fiscalyear_id = fields.Many2one( - comodel_name='account.fiscalyear', string='Fiscal year', - required=True, default=lambda s: s._default_fiscalyear_id(), - help='Only the moves in this fiscal will be exported') + selected_move_qty = fields.Integer( + string='Quantity of Selected Moves', readonly=True, + compute='_compute_move_selection', multi='move_selection') + + exported_move_ids = fields.Many2many( + string='Exported Moves', comodel_name='account.move', + compute='_compute_move_selection', multi='move_selection') + + exported_move_qty = fields.Integer( + string='Quantity of Exported Moves', readonly=True, + compute='_compute_move_selection', multi='move_selection') # Default Section @api.model def _default_fiscalyear_id(self): AccountMove = self.env['account.move'] moves = AccountMove.browse(self.env.context.get('active_ids', [])) - return self.env.context.get('active_id', False) + fiscalyears = moves.mapped('period_id.fiscalyear_id') + if len(fiscalyears) == 1: + return fiscalyears[0].id + else: + return False + + @api.multi + @api.depends('fiscalyear_id') + def _compute_move_selection(self): + for wizard in self: + wizard.selected_move_qty = len( + self.env.context.get('active_ids', [])) + wizard.exported_move_ids = wizard._get_exported_moves() + wizard.exported_move_qty = len(exported_moves.ids) + + @api.multi + def _get_exported_moves(self): + self.ensure_one() + AccountMove = self.env['account.move'] + AccountJournal = self.env['account.journal'] + domain = [('id', 'in', self.env.context.get('active_ids', []))] + # filter by state (remove draft) + domain.append(('state', '!=', 'draft')) + # filter by period (from fiscalyear) + periods = self.fiscalyear_id.period_ids + domain.append(('period_id', 'in', periods.ids)) + # Filter by journal (ebp_code should be defined) + journals = AccountJournal.search(['ebp_code', '!=', False]) + domain.append(('journal_id', 'in', journals.ids)) + # filter moves to check + domain.append(('to_check', '=', False)) + # filter yet exported moves + domain.append(('ebp_export_id', '=', False)) + return AccountMove.search(domain) + + + @api.multi + def button_export(self): + EbpExport = self.env['ebp.export'] + for wizard in self: + wizard.ebp_export_id = EbpExport.create({ + 'fiscalyear_id': wizard.fiscalyear_id.id, + }) + wizard.ebp_export_id.generate_files(wizard._get_exported_moves()) # 'company_suffix': fields.boolean( # 'Append company\'s code to accounts', @@ -93,11 +157,7 @@ def _default_fiscalyear_id(self): # 'Number of lines exported', readonly=True), # 'exported_accounts': fields.integer( # 'Number of accounts exported', readonly=True), - # 'state': fields.selection([ - # ('export_ebp', 'Prepare Export'), - # ('export_ebp_end', 'Export Done'), - # ('export_ebp_download', 'Ready to download') - # ]), + # 'empty_suffixes_partner': fields.boolean( # 'Empty Suffixes Partners', readonly=True), # 'empty_suffixes_tax': fields.boolean( From 3209929ca45d9572df0616c03d283de381710b1d Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 15 Oct 2018 20:50:04 +0200 Subject: [PATCH 05/11] [WIP] --- account_export_ebp/models/account_move.py | 13 +- account_export_ebp/models/account_tax_code.py | 42 +- account_export_ebp/models/ebp_export.py | 61 +- account_export_ebp/models/res_partner.py | 111 +-- .../views/view_account_tax_code.xml | 26 +- account_export_ebp/views/view_res_partner.xml | 25 +- account_export_ebp/wizard/__init__.py | 1 + .../wizard/view_wizard_ebp_export.xml | 56 +- .../wizard/view_wizard_ebp_unexport.xml | 5 +- .../view_wizard_res_partner_add_suffix.xml | 6 +- .../wizard/wizard_ebp_export.py | 716 +++--------------- .../wizard/wizard_ebp_unexport.py | 6 +- .../wizard/wizard_res_partner_add_suffix.py | 88 +-- .../wizard_res_partner_add_suffix_line.py | 26 + 14 files changed, 344 insertions(+), 838 deletions(-) create mode 100644 account_export_ebp/wizard/wizard_res_partner_add_suffix_line.py diff --git a/account_export_ebp/models/account_move.py b/account_export_ebp/models/account_move.py index 8e45b2f..bf480ea 100644 --- a/account_export_ebp/models/account_move.py +++ b/account_export_ebp/models/account_move.py @@ -33,9 +33,10 @@ def unlink(self): # Custom section @api.multi def _check_exported_moves(self): - exported_moves =\ - self.filtered(lambda x: x.ebp_export_id.id is not False) - if exported_moves: - raise UserError(_( - "You cannot modify or delete exported moves: %s!") - % ', '.join([m.name for m in exported_moves])) + if not self.env.context.get('force_write_ebp_exported', False): + exported_moves =\ + self.filtered(lambda x: x.ebp_export_id.id is not False) + if exported_moves: + raise UserError(_( + "You cannot modify or delete exported moves: %s!") + % ', '.join([m.name for m in exported_moves])) \ No newline at end of file diff --git a/account_export_ebp/models/account_tax_code.py b/account_export_ebp/models/account_tax_code.py index 1d1bd11..f6dda88 100644 --- a/account_export_ebp/models/account_tax_code.py +++ b/account_export_ebp/models/account_tax_code.py @@ -18,12 +18,40 @@ class AccountTaxCode(models.Model): help="When exporting Entries to EBP, this suffix will be" " appended to the Account Number to make it a new Account.") - move_line_qty = fields.Integer( - compute='_compute_move_line_qty', - string='Quantity of Account Move Lines', - help="Number of account moves for this partner") + # TODO, check if usefull + # has_ebp_no_suffix = fields.Boolean( + # string='No EBP Suffix', help="Check this box if you want to ignore" + # " the warning, when exporting into EBP move lines that have this" + # " tax code.") + has_ebp_move_line = fields.Boolean( + compute='_compute_has_ebp_move_line', + search='_search_has_ebp_move_line', + string='Has Account Move Lines exportable in EBP') + + # Columns section @api.multi - def _compute_move_line_qty(self): - pass - # AccountMoveLine = self.env['account.move.line'] + def _compute_has_ebp_move_line(self): + AccountMoveLine = self.env['account.move.line'] + for tax_code in self: + tax_code.has_ebp_move_line = len(AccountMoveLine.search([ + ('tax_code_id', '=', tax_code.id), + ('date', '>=', self._SEARCH_DATE_BEGIN)])) + + @api.model + def _search_has_ebp_move_line(self, operator, value): + assert operator in ('=', '!='), 'Invalid domain operator' + assert value in (True, False), 'Invalid domain value' + + with_line = ( + (operator == '=' and value is True) or + (operator == '!=' and value is False)) + + self._cr.execute( + "SELECT tax_code_id, count(*)" + " FROM account_move_line" + " WHERE date >= '01/12/2012'" + " GROUP BY tax_code_id" + " HAVING count(*) > 0") + res = self._cr.fetchall() + return [('id', with_line and 'in' or 'not in', [x[0] for x in res])] \ No newline at end of file diff --git a/account_export_ebp/models/ebp_export.py b/account_export_ebp/models/ebp_export.py index ad562c6..3dee3d4 100644 --- a/account_export_ebp/models/ebp_export.py +++ b/account_export_ebp/models/ebp_export.py @@ -5,8 +5,19 @@ # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +import base64 +import cStringIO +import logging + from openerp import _, api, fields, models -from openerp.Exceptions import Warning as UserError +from openerp.exceptions import Warning as UserError + +_logger = logging.getLogger(__name__) + +try: + from unidecode import unidecode +except ImportError: + _logger.debug("account_export_ebp - 'unidecode' librairy not found") class EbpExport(models.Model): @@ -25,7 +36,8 @@ class EbpExport(models.Model): readonly=True) date = fields.Datetime( - 'Date', required=True, readonly=True) + string='Date', required=True, readonly=True, + default=lambda s: s._default_date()) name = fields.Char( compute='_compute_name', string='Name', store=True, readonly=True) @@ -69,6 +81,10 @@ class EbpExport(models.Model): def _default_company_id(self): return self.env.user.company_id.id + @api.model + def _default_date(self): + return fields.Datetime.now() + # Compute Section @api.multi def _compute_name(self): @@ -95,7 +111,7 @@ def _compute_file_name_balance(self): # Custom Section @api.model - def _ebp_normalize(self, text): + def _normalize(self, text): res = text for char in self._EBP_REMOVE_CHAR_LIST: res = res.replace(char, " ") @@ -103,7 +119,7 @@ def _ebp_normalize(self, text): @api.multi def export(self, moves): - """Export moves into 3 files and mark th moves as exported""" + """Export moves into 3 files and mark the moves as exported""" self.ensure_one() # Create files moves_file = cStringIO.StringIO() @@ -114,12 +130,12 @@ def export(self, moves): self._write_header_into_moves_file(moves_file) self._write_header_into_balance_file(balance_file) - self._export_to_files(moves, move_file, account_file, balance_file) + self._export_to_files(moves, moves_file, accounts_file, balance_file) data_moves = base64.encodestring(moves_file.getvalue()) - data_accounts = base64.encodestring(account_file.getvalue()) + data_accounts = base64.encodestring(accounts_file.getvalue()) data_balance = base64.encodestring(balance_file.getvalue()) moves_file.close() - account_file.close() + accounts_file.close() balance_file.close() # Save Datas @@ -135,7 +151,8 @@ def export(self, moves): }) @api.model - def _export_to_files(self, moves, move_file, account_file, balance_file): + def _export_to_files( + self, moves, moves_file, accounts_file, balance_file): # dictionary to store accounts while we loop through move lines accounts_data = {} # Line counter @@ -175,11 +192,9 @@ def _export_to_files(self, moves, move_file, account_file, balance_file): self._write_into_moves_file(i, moves_data, moves_file) i += len(moves_data) - # Write the accounts into the file self._write_into_accounts_file(i, accounts_data, accounts_file) - # # Write the balance of accounts into the file self._write_into_balance_file(i, accounts_data, balance_file) @@ -286,7 +301,7 @@ def _prepare_move_line_dict(self, move, line): } @api.model - def _write_into_moves_file(count, moves_data, moves_file): + def _write_into_moves_file(self, count, moves_data, moves_file): i = count for account_code, line in moves_data.iteritems(): @@ -393,11 +408,12 @@ def _prepare_account_dict(self, move, line): else: # Normal account res.update({ - 'name': self._normalize(line.account_id.name), + 'name': self._normalize(line.account_id.name), }) + return res @api.model - def _write_into_accounts_file(count, accounts_data, accounts_file): + def _write_into_accounts_file(self, count, accounts_data, accounts_file): for account_code, account_data in accounts_data.iteritems(): data = [ account_code.replace(',', ''), @@ -414,10 +430,10 @@ def _write_into_accounts_file(count, accounts_data, accounts_file): self._write_into_file(data, accounts_file) @api.model - def _write_into_balance_file(count, accounts_data, balance_file): + def _write_into_balance_file(self, count, accounts_data, balance_file): for account_code, account_data in accounts_data.iteritems(): - credit = (account['credit'] or 0) - debit = (account['debit'] or 0) + credit = (account_data['credit'] or 0) + debit = (account_data['debit'] or 0) if credit > debit: credit_balance = credit - debit debit_balance = 0 @@ -426,7 +442,7 @@ def _write_into_balance_file(count, accounts_data, balance_file): debit_balance = debit - credit data = [ account_code.replace(',', ''), - (account['name'] or '').replace(',', '')[:60], + (account_data['name'] or '').replace(',', '')[:60], str(debit), str(credit), str(debit_balance), @@ -436,7 +452,8 @@ def _write_into_balance_file(count, accounts_data, balance_file): @api.model def _write_into_file(self, data_list, file): - file.write(unidecode(','.join(data_list))) + tmp = ','.join(data_list) + file.write(tmp) file.write('\r\n') # _logger.debug( @@ -457,12 +474,6 @@ def _write_into_file(self, data_list, file): # }, context=context) # return export_id - - - - - - # FILE # FUCK ANALYTIC @@ -474,8 +485,6 @@ def _write_into_file(self, data_list, file): # if is_analytic_column: # move_line += ',Poste analytique' - - # AH BON ???? # if len(move.name) > 15: # raise osv.except_osv(_('Move name too long'), _( diff --git a/account_export_ebp/models/res_partner.py b/account_export_ebp/models/res_partner.py index 880ae08..2398051 100644 --- a/account_export_ebp/models/res_partner.py +++ b/account_export_ebp/models/res_partner.py @@ -6,91 +6,56 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp import _, api, fields, models -from openerp.exceptions import Warning as UserError +from openerp import api, fields, models class ResPartner(models.Model): _inherit = 'res.partner' + _SEARCH_DATE_BEGIN = '01/12/2012' + # Columns section ebp_suffix = fields.Char( string="Suffix in EBP", oldname="ref_nb", help="When exporting Entries to EBP, this suffix will be" " appended to the Account Number to make it a Partner Account.") - move_line_qty = fields.Integer( - compute='_compute_move_line_qty', - string='Quantity of Account Move Lines', - help="Number of account moves for this partner") + has_ebp_move_line = fields.Boolean( + compute='_compute_has_ebp_move_line', + search='_search_has_ebp_move_line', + string='Has Account Move Lines exportable in EBP') + + # Constraints section + _sql_constraints = [ + ( + 'ebp_suffix_company_id_uniq', + 'unique (ebp_suffix, company_id)', + 'The EBP suffix must be unique per company!') + ] # Columns section @api.multi - def _compute_move_line_qty(self): + def _compute_has_ebp_move_line(self): AccountMoveLine = self.env['account.move.line'] - # for aId in ids: - # aml_ids = aml_obj.search(cr, uid, [ - # ('partner_id', '=', aId), ('date', '>=', '01/12/2012')], - # context=context) - # res[aId] = len(aml_ids) - # return res - # TODO -# -# Search Section - # def _search_ean_duplicates_exist(self, operator, operand): - # products = self.search([]) - # res = products._get_ean_duplicates() - # if operator == '=' and operand is True: - # product_ids = res.keys() - # elif operator == '=' and operand is False: - # product_ids = list(set(products.ids) - set(res.keys())) - # else: - # raise UserError(_( - # "Operator '%s' not implemented.") % (operator)) - # return [('id', 'in', product_ids)] -# -# - # def _search_move_line_qty(self, cr, uid, obj, name, args, context=None): - # if not args: - # return [] - # query, query_args = self._get_search_moves_query( - # cr, uid, args, overdue_only=False, context=context) - # cr.execute(query, query_args) - # res = cr.fetchall() - # if not res: - # return [('id', '=', '0')] - # return [('id', 'in', [x[0] for x in res])] -# - # _columns = { - # Partner's account number in EBP -# - # } -# - # Constraints section - # _sql_constraints = [ - # ( - # 'partner_suffix_uniq', - # 'unique (ref_nb, company_id)', - # 'The partner suffix must be unique per company!') - # ] -# - # Overloading section - # def write(self, cr, uid, ids, vals, context=None): - # ref_nb = vals.get('ref_nb', False) - # if ref_nb: - # vals['ref_nb'] = ref_nb.upper() - # return super(res_partner, self).write( - # cr, uid, ids, vals, context=context) -# - # Private section - # def _get_search_moves_query( - # self, cr, uid, args, overdue_only=False, context=None): - # having_where_clause = ' AND '.join( - # map(lambda x: '(COUNT(*) %s %%s)' % (x[1]), args)) - # having_values = [x[2] for x in args] - # return """ - # SELECT partner_id, count(*) - # FROM account_move_line - # WHERE date >= '01/12/2012' - # GROUP BY partner_id - # HAVING """ + having_where_clause, having_values + for partner in self: + partner.has_ebp_move_line = len(AccountMoveLine.search([ + ('partner_id', '=', partner.id), + ('date', '>=', self._SEARCH_DATE_BEGIN)])) + + @api.model + def _search_has_ebp_move_line(self, operator, value): + assert operator in ('=', '!='), 'Invalid domain operator' + assert value in (True, False), 'Invalid domain value' + + with_line = ( + (operator == '=' and value is True) or + (operator == '!=' and value is False)) + + self._cr.execute( + "SELECT partner_id, count(*)" + " FROM account_move_line" + " WHERE date >= '01/12/2012'" + " GROUP BY partner_id" + " HAVING count(*) > 0") + res = self._cr.fetchall() + return [('id', with_line and 'in' or 'not in', [x[0] for x in res])] diff --git a/account_export_ebp/views/view_account_tax_code.xml b/account_export_ebp/views/view_account_tax_code.xml index d2d74be..f0954e9 100644 --- a/account_export_ebp/views/view_account_tax_code.xml +++ b/account_export_ebp/views/view_account_tax_code.xml @@ -10,14 +10,16 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). account.tax.code - - + + +
@@ -27,7 +29,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - +
@@ -39,7 +41,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + @@ -52,7 +54,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). form tree - {'search_default_with_moves': 1, 'search_default_no_suffix': 1} + {'search_default_without_suffix_with_move_line_ebp': 1} - + \ No newline at end of file diff --git a/account_export_ebp/views/view_res_partner.xml b/account_export_ebp/views/view_res_partner.xml index b8be760..b2dcac0 100644 --- a/account_export_ebp/views/view_res_partner.xml +++ b/account_export_ebp/views/view_res_partner.xml @@ -6,8 +6,6 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). --> - - res.partner @@ -24,14 +22,16 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - + + + @@ -42,7 +42,8 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - + + @@ -57,7 +58,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). form tree - {'search_default_with_moves': 1,'search_default_no_suffix': 1} + {'search_default_without_suffix_with_move_line_ebp': 1}
- + +

You have selected moves related to partners without EBP suffixes defined.

+ +

You have selected draft moves.

+ +

You have selected moves that doesn't belong to the selected fiscal year.

+ +

You have selected moves that belong to a journal that doesn't have a correct 'EBP code' set.

+ +

You have selected moves that are marked as 'To check'.

+ +

You have selected moves that have already been exported in EBP.

+
+ + -
-
- + +
+
diff --git a/account_export_ebp/wizard/view_wizard_ebp_unexport.xml b/account_export_ebp/wizard/view_wizard_ebp_unexport.xml index 787c4b6..af1e158 100644 --- a/account_export_ebp/wizard/view_wizard_ebp_unexport.xml +++ b/account_export_ebp/wizard/view_wizard_ebp_unexport.xml @@ -10,8 +10,9 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). wizard.ebp.unexport
-

The export will be canceled for the selected moves.

-

Be sure to delete the corresponding lines in EBP.

+

+ The export will be canceled for the selected moves. Be sure to delete the corresponding lines in EBP. +