diff --git a/account_easy_reconcile/README.rst b/account_easy_reconcile/README.rst index 39e6b2c9..b603301a 100644 --- a/account_easy_reconcile/README.rst +++ b/account_easy_reconcile/README.rst @@ -42,9 +42,22 @@ Credits Contributors ------------ - -* Damien Crier +* Sébastien Beau +* Guewen Baconnier +* Vincent Renaville +* Alexandre Fayolle +* Joël Grand-Guillaume +* Nicolas Bessis +* Pedro M.Baeza +* Matthieu Dietrich +* Leonardo Pistone +* Ecino +* Yannick Vaucher +* Rudolf Schnapka +* Florian Dacosta +* Laetitia Gangloff * Frédéric Clémenti +* Damien Crier Maintainer ---------- diff --git a/account_easy_reconcile/__openerp__.py b/account_easy_reconcile/__openerp__.py index df579062..472b977d 100755 --- a/account_easy_reconcile/__openerp__.py +++ b/account_easy_reconcile/__openerp__.py @@ -25,34 +25,6 @@ "version": "1.3.1", "depends": ["account"], "author": "Akretion,Camptocamp,Odoo Community Association (OCA)", - "description": """ -Easy Reconcile -============== - -This is a shared work between Akretion and Camptocamp -in order to provide: - - reconciliation facilities for big volume of transactions - - setup different profiles of reconciliation by account - - each profile can use many methods of reconciliation - - this module is also a base to create others - reconciliation methods which can plug in the profiles - - a profile a reconciliation can be run manually - or by a cron - - monitoring of reconciliation runs with an history - which keep track of the reconciled Journal items - -2 simple reconciliation methods are integrated -in this module, the simple reconciliations works -on 2 lines (1 debit / 1 credit) and do not allow -partial reconcilation, they also match on 1 key, -partner or Journal item name. - -You may be interested to install also the -``account_advanced_reconciliation`` module. -This latter add more complex reconciliations, -allows multiple lines and partial. - -""", "website": "http://www.akretion.com/", "category": "Finance", "data": ["easy_reconcile.xml", diff --git a/account_easy_reconcile/base_reconciliation.py b/account_easy_reconcile/base_reconciliation.py index 787f0f76..16843f77 100644 --- a/account_easy_reconcile/base_reconciliation.py +++ b/account_easy_reconcile/base_reconciliation.py @@ -78,9 +78,11 @@ class EasyReconcileBase(models.AbstractModel): 'move_id') return ["account_move_line.%s" % col for col in aml_cols] + @api.multi def _select(self, *args, **kwargs): return "SELECT %s" % ', '.join(self._base_columns()) + @api.multi def _from(self, *args, **kwargs): return ("FROM account_move_line " "LEFT OUTER JOIN account_move_reconcile ON " @@ -88,6 +90,7 @@ class EasyReconcileBase(models.AbstractModel): "= account_move_reconcile.id)" ) + @api.multi def _where(self, *args, **kwargs): where = ("WHERE account_move_line.account_id = %s " "AND COALESCE(account_move_reconcile.type,'') <> 'manual' " @@ -102,8 +105,9 @@ class EasyReconcileBase(models.AbstractModel): params.append(tuple([l.id for l in self.partner_ids])) return where, params + @api.multi def _get_filter(self): - ml_obj = self.pool.get('account.move.line') + ml_obj = self.env['account.move.line'] where = '' params = [] if self.filter: @@ -116,7 +120,7 @@ class EasyReconcileBase(models.AbstractModel): @api.multi def _below_writeoff_limit(self, lines, writeoff_limit): self.ensure_one() - precision = self.pool.get('decimal.precision').precision_get('Account') + precision = self.env['decimal.precision'].precision_get('Account') keys = ('debit', 'credit') sums = reduce( lambda line, memo: @@ -134,7 +138,8 @@ class EasyReconcileBase(models.AbstractModel): def last_period(mlines): period_ids = [ml['period_id'] for ml in mlines] - return max(period_ids, key=attrgetter('date_stop')) + periods = self.env['account.period'].browse(period_ids) + return max(periods, key=attrgetter('date_stop')) def last_date(mlines): return max(mlines, key=itemgetter('date')) @@ -175,13 +180,12 @@ class EasyReconcileBase(models.AbstractModel): """ self.ensure_one() ml_obj = self.env['account.move.line'] - writeoff = self.write_off line_ids = [l['id'] for l in lines] below_writeoff, sum_debit, sum_credit = self._below_writeoff_limit( - lines, writeoff + lines, self.write_off ) date = self._get_rec_date(lines, self.date_base_on) - rec_ctx = dict(self.env.context or {}, date_p=date) + rec_ctx = dict(self.env.context, date_p=date) if below_writeoff: if sum_credit > sum_debit: writeoff_account_id = self.account_profit_id.id @@ -190,11 +194,11 @@ class EasyReconcileBase(models.AbstractModel): period_id = self.env['account.period'].find(dt=date)[0] if self.analytic_account_id: rec_ctx['analytic_id'] = self.analytic_account_id.id - ml_obj.with_context(rec_ctx).reconcile( - line_ids, + line_rs = ml_obj.browse(line_ids) + line_rs.with_context(rec_ctx).reconcile( type='auto', writeoff_acc_id=writeoff_account_id, - writeoff_period_id=period_id, + writeoff_period_id=period_id.id, writeoff_journal_id=self.journal_id.id ) return True, True @@ -226,12 +230,12 @@ class EasyReconcileBase(models.AbstractModel): period_id = self.env['account.period'].find(dt=date)[0] if self.analytic_account_id: rec_ctx['analytic_id'] = self.analytic_account_id.id - ml_obj.with_context(rec_ctx).reconcile_partial( - line_ids, + line_rs = ml_obj.browse(line_ids) + line_rs.with_context(rec_ctx).reconcile( type='manual', writeoff_acc_id=writeoff_account_id, - writeoff_period_id=period_id, - writeoff_journal_id=self.journal_id.id, + writeoff_period_id=period_id.id, + writeoff_journal_id=self.journal_id.id ) return True, False return False, False diff --git a/account_easy_reconcile/easy_reconcile.py b/account_easy_reconcile/easy_reconcile.py index 376a056e..0a8f50ed 100644 --- a/account_easy_reconcile/easy_reconcile.py +++ b/account_easy_reconcile/easy_reconcile.py @@ -22,8 +22,7 @@ from datetime import datetime from openerp import models, api, fields, _ -from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT -from openerp.exceptions import except_orm +from openerp.exceptions import Warning from openerp import sql_db # from openerp import pooler @@ -65,16 +64,16 @@ class EasyReconcileOptions(models.AbstractModel): required=True, string='Date of reconciliation', default='end_period_last_credit') - filter = fields.Char(string='Filter', size=128) + filter = fields.Char(string='Filter') analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic_account', - help="Analytic account" + help="Analytic account " "for the write-off") income_exchange_account_id = fields.Many2one('account.account', - string='Gain Exchange' + string='Gain Exchange ' 'Rate Account') expense_exchange_account_id = fields.Many2one('account.account', - string='Loss Exchange' + string='Loss Exchange ' 'Rate Account') @@ -116,23 +115,6 @@ class AccountEasyReconcileMethod(models.Model): readonly=True ) -# def init(self, cr): -# """ Migration stuff -# -# Name is not anymore methods names but the name -# of the model which does the reconciliation -# """ -# cr.execute(""" -# UPDATE account_easy_reconcile_method -# SET name = 'easy.reconcile.simple.partner' -# WHERE name = 'action_rec_auto_partner' -# """) -# cr.execute(""" -# UPDATE account_easy_reconcile_method -# SET name = 'easy.reconcile.simple.name' -# WHERE name = 'action_rec_auto_name' -# """) - class AccountEasyReconcile(models.Model): @@ -144,21 +126,21 @@ class AccountEasyReconcile(models.Model): @api.depends('account') def _get_total_unrec(self): obj_move_line = self.env['account.move.line'] - self.unreconciled_count = len(obj_move_line.search( + self.unreconciled_count = obj_move_line.search_count( [('account_id', '=', self.account.id), ('reconcile_id', '=', False), ('reconcile_partial_id', '=', False)], - )) + ) @api.one @api.depends('account') def _get_partial_rec(self): obj_move_line = self.env['account.move.line'] - self.reconciled_partial_count = len(obj_move_line.search( + self.reconciled_partial_count = obj_move_line.search_count( [('account_id', '=', self.account.id), ('reconcile_id', '=', False), ('reconcile_partial_id', '!=', False)], - )) + ) @api.one @api.depends('history_ids') @@ -171,9 +153,9 @@ class AccountEasyReconcile(models.Model): [('easy_reconcile_id', '=', self.id)], limit=1, order='date desc' ) - self.last_history = last_history_rs[0] if last_history_rs else False + self.last_history = last_history_rs or False - name = fields.Char(string='Name', size=32, required=True) + name = fields.Char(string='Name', required=True) account = fields.Many2one('account.account', string='Account', required=True, @@ -197,7 +179,6 @@ class AccountEasyReconcile(models.Model): last_history = fields.Many2one('easy.reconcile.history', string='readonly=True', compute='_last_history', - readonly=True ) company_id = fields.Many2one('res.company', string='Company') @@ -205,20 +186,14 @@ class AccountEasyReconcile(models.Model): def _prepare_run_transient(self, rec_method): return {'account_id': rec_method.task_id.account.id, 'write_off': rec_method.write_off, - 'account_lost_id': (rec_method.account_lost_id and - rec_method.account_lost_id.id), - 'account_profit_id': (rec_method.account_profit_id and - rec_method.account_profit_id.id), - 'analytic_account_id': (rec_method.analytic_account_id and - rec_method.analytic_account_id.id), + 'account_lost_id': (rec_method.account_lost_id.id), + 'account_profit_id': (rec_method.account_profit_id.id), + 'analytic_account_id': (rec_method.analytic_account_id.id), 'income_exchange_account_id': - (rec_method.income_exchange_account_id and - rec_method.income_exchange_account_id.id), + (rec_method.income_exchange_account_id.id), 'expense_exchange_account_id': - (rec_method.income_exchange_account_id and - rec_method.income_exchange_account_id.id), - 'journal_id': (rec_method.journal_id and - rec_method.journal_id.id), + (rec_method.income_exchange_account_id.id), + 'journal_id': (rec_method.journal_id.id), 'date_base_on': rec_method.date_base_on, 'filter': rec_method.filter} @@ -305,7 +280,7 @@ class AccountEasyReconcile(models.Model): self.env['easy.reconcile.history'].create( { 'easy_reconcile_id': rec.id, - 'date': fields.datetime.now(), + 'date': fields.Datetime.now(), 'reconcile_ids': [], 'reconcile_partial_ids': [], } @@ -315,8 +290,6 @@ class AccountEasyReconcile(models.Model): new_cr.commit() new_cr.close() -# self.env.cr.close() - return True @api.model @@ -325,10 +298,10 @@ class AccountEasyReconcile(models.Model): be called when there is no history on the reconciliation task. """ - raise except_orm( - _('Error'), + raise Warning( _('There is no history of reconciled ' - 'items on the task: %s.') % rec.name) + 'items on the task: %s.') % rec.name + ) @api.model def _open_move_line_list(self, move_line_ids, name): @@ -349,52 +322,42 @@ class AccountEasyReconcile(models.Model): """ Open the view of move line with the unreconciled move lines""" self.ensure_one() obj_move_line = self.env['account.move.line'] - line_ids = obj_move_line.search( + lines = obj_move_line.search( [('account_id', '=', self.account.id), ('reconcile_id', '=', False), ('reconcile_partial_id', '=', False)]) name = _('Unreconciled items') - return self._open_move_line_list(line_ids and line_ids.ids or [], name) + return self._open_move_line_list(lines.ids or [], name) @api.multi def open_partial_reconcile(self): """ Open the view of move line with the unreconciled move lines""" self.ensure_one() obj_move_line = self.env['account.move.line'] - line_ids = obj_move_line.search( + lines = obj_move_line.search( [('account_id', '=', self.account.id), ('reconcile_id', '=', False), ('reconcile_partial_id', '!=', False)]) name = _('Partial reconciled items') - return self._open_move_line_list(line_ids and line_ids.ids or [], name) + return self._open_move_line_list(lines.ids or [], name) - @api.model - def last_history_reconcile(self, rec_id): + @api.multi + def last_history_reconcile(self): """ Get the last history record for this reconciliation profile and return the action which opens move lines reconciled """ - if isinstance(rec_id, (tuple, list)): - assert len(rec_id) == 1, \ - "Only 1 id expected" - rec_id = rec_id[0] - rec = self.browse(rec_id) - if not rec.last_history: - self._no_history(rec) - return rec.last_history.open_reconcile() + if not self.last_history: + self._no_history() + return self.last_history.open_reconcile() - @api.model - def last_history_partial(self, rec_id): + @api.multi + def last_history_partial(self): """ Get the last history record for this reconciliation profile and return the action which opens move lines reconciled """ - if isinstance(rec_id, (tuple, list)): - assert len(rec_id) == 1, \ - "Only 1 id expected" - rec_id = rec_id[0] - rec = self.browse(rec_id) - if not rec.last_history: - self._no_history(rec) - return rec.last_history.open_partial() + if not self.last_history: + self._no_history() + return self.last_history.open_partial() @api.model def run_scheduler(self, run_all=None): @@ -408,8 +371,7 @@ class AccountEasyReconcile(models.Model): """ def _get_date(reconcile): if reconcile.last_history.date: - return datetime.strptime(reconcile.last_history.date, - DEFAULT_SERVER_DATETIME_FORMAT) + return fields.Datetime.from_string(reconcile.last_history.date) else: return datetime.min diff --git a/account_easy_reconcile/easy_reconcile.xml b/account_easy_reconcile/easy_reconcile.xml index 076bd3b3..7de62cbc 100644 --- a/account_easy_reconcile/easy_reconcile.xml +++ b/account_easy_reconcile/easy_reconcile.xml @@ -136,7 +136,7 @@ The lines should have the same amount (with the write-off) and the same referenc - + @@ -156,7 +156,7 @@ The lines should have the same amount (with the write-off) and the same referenc - + diff --git a/account_easy_reconcile/easy_reconcile_history.py b/account_easy_reconcile/easy_reconcile_history.py index 3990f675..b8a2c010 100644 --- a/account_easy_reconcile/easy_reconcile_history.py +++ b/account_easy_reconcile/easy_reconcile_history.py @@ -36,15 +36,14 @@ class EasyReconcileHistory(models.Model): def _reconcile_line_ids(self): move_line_ids = [] for reconcile in self.reconcile_ids: - move_line_ids += [line.id - for line - in reconcile.line_id] + move_lines = reconcile.mapped('line_id') + move_line_ids.extend(move_lines.ids) self.reconcile_line_ids = move_line_ids + move_line_ids = [] for reconcile in self.reconcile_partial_ids: - move_line_ids += [line.id - for line - in reconcile.line_partial_ids] + move_lines = reconcile.mapped('line_partial_ids') + move_line_ids.extend(move_lines.ids) self.partial_line_ids = move_line_ids easy_reconcile_id = fields.Many2one( @@ -69,15 +68,13 @@ class EasyReconcileHistory(models.Model): comodel_name='account.move.line', relation='account_move_line_history_rel', string='Reconciled Items', - readonly=True, multi='lines', _compute='_reconcile_line_ids' ) partial_line_ids = fields.Many2many( comodel_name='account.move.line', - relation='account_move_line_history_rel', + relation='account_move_line_history_partial_rel', string='Partially Reconciled Items', - readonly=True, multi='lines', _compute='_reconcile_line_ids' ) @@ -99,14 +96,19 @@ class EasyReconcileHistory(models.Model): """ assert rec_type in ('full', 'partial'), \ "rec_type must be 'full' or 'partial'" - history = self + move_line_ids = [] if rec_type == 'full': - field = 'reconcile_line_ids' + move_line_ids = [] + for reconcile in self.reconcile_ids: + move_lines = reconcile.mapped('line_id') + move_line_ids.extend(move_lines.ids) name = _('Reconciliations') else: - field = 'partial_line_ids' + move_line_ids = [] + for reconcile in self.reconcile_partial_ids: + move_lines = reconcile.mapped('line_partial_ids') + move_line_ids.extend(move_lines.ids) name = _('Partial Reconciliations') - move_line_ids = [line.id for line in getattr(history, field)] return { 'name': name, 'view_mode': 'tree,form', @@ -119,6 +121,7 @@ class EasyReconcileHistory(models.Model): 'domain': unicode([('id', 'in', move_line_ids)]), } + @api.multi def open_reconcile(self): """ For an history record, open the view of move line with the reconciled move lines @@ -130,7 +133,7 @@ class EasyReconcileHistory(models.Model): self.ensure_one() return self._open_move_lines(rec_type='full') - @api.model + @api.multi def open_partial(self): """ For an history record, open the view of move line with the partially reconciled move lines diff --git a/account_easy_reconcile/res_config.py b/account_easy_reconcile/res_config.py index 36265a91..e4e16da0 100644 --- a/account_easy_reconcile/res_config.py +++ b/account_easy_reconcile/res_config.py @@ -28,7 +28,7 @@ class AccountConfigSettings(models.TransientModel): reconciliation_commit_every = fields.Integer( related="company_id.reconciliation_commit_every", - string="How often to commit when performing automatic" + string="How often to commit when performing automatic " "reconciliation.", help="""Leave zero to commit only at the end of the process.""" ) @@ -52,7 +52,7 @@ class Company(models.Model): _inherit = "res.company" reconciliation_commit_every = fields.Integer( - string="How often to commit when performing automatic" + string="How often to commit when performing automatic " "reconciliation.", - help="""Leave zero to commit only at the end of the process.""" + help="Leave zero to commit only at the end of the process." ) diff --git a/account_easy_reconcile/simple_reconciliation.py b/account_easy_reconcile/simple_reconciliation.py index 8cd12091..b54ffd03 100644 --- a/account_easy_reconcile/simple_reconciliation.py +++ b/account_easy_reconcile/simple_reconciliation.py @@ -54,7 +54,6 @@ class EasyReconcileSimple(models.AbstractModel): if not check: continue reconciled, dummy = self._reconcile_lines( - self, [credit_line, debit_line], allow_partial=False ) @@ -65,6 +64,7 @@ class EasyReconcileSimple(models.AbstractModel): count += 1 return res, [] # empty list for partial, only full rec in "simple" rec + @api.multi def _simple_order(self, *args, **kwargs): return "ORDER BY account_move_line.%s" % self._key_field