+
+Maintainer
+----------
+
+.. image:: https://odoo-community.org/logo.png
+ :alt: Odoo Community Association
+ :target: https://odoo-community.org
+
+This module is maintained by the OCA.
+
+OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
+To contribute to this module, please visit http://odoo-community.org.
+
diff --git a/__unported__/account_easy_reconcile/__init__.py b/account_easy_reconcile/__init__.py
similarity index 93%
rename from __unported__/account_easy_reconcile/__init__.py
rename to account_easy_reconcile/__init__.py
index 0b0a2b53..3ac78713 100755
--- a/__unported__/account_easy_reconcile/__init__.py
+++ b/account_easy_reconcile/__init__.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Copyright 2012 Camptocamp SA (Guewen Baconnier)
+# Copyright 2012, 2015 Camptocamp SA (Guewen Baconnier, Damien Crier)
# Copyright (C) 2010 Sébastien Beau
#
# This program is free software: you can redistribute it and/or modify
diff --git a/__unported__/account_easy_reconcile/__openerp__.py b/account_easy_reconcile/__openerp__.py
similarity index 56%
rename from __unported__/account_easy_reconcile/__openerp__.py
rename to account_easy_reconcile/__openerp__.py
index abe1124b..36b54948 100755
--- a/__unported__/account_easy_reconcile/__openerp__.py
+++ b/account_easy_reconcile/__openerp__.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Copyright 2012 Camptocamp SA (Guewen Baconnier)
+# Copyright 2012, 2015 Camptocamp SA (Guewen Baconnier, Damien Crier)
# Copyright (C) 2010 Sébastien Beau
#
# This program is free software: you can redistribute it and/or modify
@@ -24,45 +24,18 @@
"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",
- "demo_xml": [],
"data": ["easy_reconcile.xml",
"easy_reconcile_history_view.xml",
"security/ir_rule.xml",
"security/ir.model.access.csv",
"res_config_view.xml",
],
+ "test": ['test/easy_reconcile.yml',
+ ],
'license': 'AGPL-3',
"auto_install": False,
- 'installable': False,
+ 'installable': True,
}
diff --git a/__unported__/account_easy_reconcile/base_reconciliation.py b/account_easy_reconcile/base_reconciliation.py
similarity index 64%
rename from __unported__/account_easy_reconcile/base_reconciliation.py
rename to account_easy_reconcile/base_reconciliation.py
index 35ce4920..83048334 100644
--- a/__unported__/account_easy_reconcile/base_reconciliation.py
+++ b/account_easy_reconcile/base_reconciliation.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Copyright 2012-2013 Camptocamp SA (Guewen Baconnier)
+# Copyright 2012-2013, 2015 Camptocamp SA (Guewen Baconnier, Damien Crier)
# Copyright (C) 2010 Sébastien Beau
#
# This program is free software: you can redistribute it and/or modify
@@ -19,11 +19,12 @@
#
##############################################################################
-from openerp.osv import fields, orm
+from openerp import models, api, fields
+from openerp.tools.safe_eval import safe_eval
from operator import itemgetter, attrgetter
-class EasyReconcileBase(orm.AbstractModel):
+class EasyReconcileBase(models.AbstractModel):
"""Abstract Model for reconciliation methods"""
@@ -31,33 +32,35 @@ class EasyReconcileBase(orm.AbstractModel):
_inherit = 'easy.reconcile.options'
- _columns = {
- 'account_id': fields.many2one(
- 'account.account', 'Account', required=True),
- 'partner_ids': fields.many2many(
- 'res.partner', string="Restrict on partners"),
- # other columns are inherited from easy.reconcile.options
- }
+ account_id = fields.Many2one(
+ 'account.account',
+ string='Account',
+ required=True
+ )
+ partner_ids = fields.Many2many(
+ comodel_name='res.partner',
+ string='Restrict on partners',
+ )
+ # other fields are inherited from easy.reconcile.options
- def automatic_reconcile(self, cr, uid, ids, context=None):
+ @api.multi
+ def automatic_reconcile(self):
""" Reconciliation method called from the view.
:return: list of reconciled ids, list of partially reconciled items
"""
- if isinstance(ids, (int, long)):
- ids = [ids]
- assert len(ids) == 1, "Has to be called on one id"
- rec = self.browse(cr, uid, ids[0], context=context)
- return self._action_rec(cr, uid, rec, context=context)
+ self.ensure_one()
+ return self._action_rec()
- def _action_rec(self, cr, uid, rec, context=None):
+ @api.multi
+ def _action_rec(self):
""" Must be inherited to implement the reconciliation
:return: list of reconciled ids
"""
raise NotImplementedError
- def _base_columns(self, rec):
+ def _base_columns(self):
""" Mandatory columns for move lines queries
An extra column aliased as ``key`` should be defined
in each query."""
@@ -75,17 +78,20 @@ class EasyReconcileBase(orm.AbstractModel):
'move_id')
return ["account_move_line.%s" % col for col in aml_cols]
- def _select(self, rec, *args, **kwargs):
- return "SELECT %s" % ', '.join(self._base_columns(rec))
+ @api.multi
+ def _select(self, *args, **kwargs):
+ return "SELECT %s" % ', '.join(self._base_columns())
- def _from(self, rec, *args, **kwargs):
+ @api.multi
+ def _from(self, *args, **kwargs):
return ("FROM account_move_line "
"LEFT OUTER JOIN account_move_reconcile ON "
"(account_move_line.reconcile_partial_id "
"= account_move_reconcile.id)"
)
- def _where(self, rec, *args, **kwargs):
+ @api.multi
+ def _where(self, *args, **kwargs):
where = ("WHERE account_move_line.account_id = %s "
"AND COALESCE(account_move_reconcile.type,'') <> 'manual' "
"AND account_move_line.reconcile_id IS NULL ")
@@ -93,27 +99,28 @@ class EasyReconcileBase(orm.AbstractModel):
# but as we use _where_calc in _get_filter
# which returns a list, we have to
# accomodate with that
- params = [rec.account_id.id]
- if rec.partner_ids:
+ params = [self.account_id.id]
+ if self.partner_ids:
where += " AND account_move_line.partner_id IN %s"
- params.append(tuple([l.id for l in rec.partner_ids]))
+ params.append(tuple([l.id for l in self.partner_ids]))
return where, params
- def _get_filter(self, cr, uid, rec, context):
- ml_obj = self.pool.get('account.move.line')
+ @api.multi
+ def _get_filter(self):
+ ml_obj = self.env['account.move.line']
where = ''
params = []
- if rec.filter:
+ if self.filter:
dummy, where, params = ml_obj._where_calc(
- cr, uid, eval(rec.filter), context=context).get_sql()
+ safe_eval(self.filter)).get_sql()
if where:
where = " AND %s" % where
return where, params
- def _below_writeoff_limit(self, cr, uid, rec, lines,
- writeoff_limit, context=None):
- precision = self.pool.get('decimal.precision').precision_get(
- cr, uid, 'Account')
+ @api.multi
+ def _below_writeoff_limit(self, lines, writeoff_limit):
+ self.ensure_one()
+ precision = self.env['decimal.precision'].precision_get('Account')
keys = ('debit', 'credit')
sums = reduce(
lambda line, memo:
@@ -125,14 +132,13 @@ class EasyReconcileBase(orm.AbstractModel):
writeoff_amount = round(debit - credit, precision)
return bool(writeoff_limit >= abs(writeoff_amount)), debit, credit
- def _get_rec_date(self, cr, uid, rec, lines,
- based_on='end_period_last_credit', context=None):
- period_obj = self.pool['account.period']
+ @api.multi
+ def _get_rec_date(self, lines, based_on='end_period_last_credit'):
+ self.ensure_one()
def last_period(mlines):
period_ids = [ml['period_id'] for ml in mlines]
- periods = period_obj.browse(
- cr, uid, period_ids, context=context)
+ periods = self.env['account.period'].browse(period_ids)
return max(periods, key=attrgetter('date_stop'))
def last_date(mlines):
@@ -158,8 +164,8 @@ class EasyReconcileBase(orm.AbstractModel):
# when date is None
return None
- def _reconcile_lines(self, cr, uid, rec, lines, allow_partial=False,
- context=None):
+ @api.multi
+ def _reconcile_lines(self, lines, allow_partial=False):
""" Try to reconcile given lines
:param list lines: list of dict of move lines, they must at least
@@ -172,33 +178,29 @@ class EasyReconcileBase(orm.AbstractModel):
the second is wether the reconciliation is full (True)
or partial (False)
"""
- if context is None:
- context = {}
- ml_obj = self.pool.get('account.move.line')
- writeoff = rec.write_off
+ self.ensure_one()
+ ml_obj = self.env['account.move.line']
line_ids = [l['id'] for l in lines]
below_writeoff, sum_debit, sum_credit = self._below_writeoff_limit(
- cr, uid, rec, lines, writeoff, context=context)
- date = self._get_rec_date(
- cr, uid, rec, lines, rec.date_base_on, context=context)
- rec_ctx = dict(context, date_p=date)
+ lines, self.write_off
+ )
+ date = self._get_rec_date(lines, self.date_base_on)
+ rec_ctx = dict(self.env.context, date_p=date)
if below_writeoff:
if sum_credit > sum_debit:
- writeoff_account_id = rec.account_profit_id.id
+ writeoff_account_id = self.account_profit_id.id
else:
- writeoff_account_id = rec.account_lost_id.id
- period_id = self.pool.get('account.period').find(
- cr, uid, dt=date, context=context)[0]
- if rec.analytic_account_id:
- rec_ctx['analytic_id'] = rec.analytic_account_id.id
- ml_obj.reconcile(
- cr, uid,
- line_ids,
+ writeoff_account_id = self.account_lost_id.id
+ period_id = self.env['account.period'].find(dt=date)[0]
+ if self.analytic_account_id:
+ rec_ctx['analytic_id'] = self.analytic_account_id.id
+ 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_journal_id=rec.journal_id.id,
- context=rec_ctx)
+ writeoff_period_id=period_id.id,
+ writeoff_journal_id=self.journal_id.id
+ )
return True, True
elif allow_partial:
# Check if the group of move lines was already partially
@@ -209,9 +211,8 @@ class EasyReconcileBase(orm.AbstractModel):
existing_partial_id = lines[0]['reconcile_partial_id']
if existing_partial_id:
partial_line_ids = set(ml_obj.search(
- cr, uid,
[('reconcile_partial_id', '=', existing_partial_id)],
- context=context))
+ ))
if set(line_ids) == partial_line_ids:
return True, False
@@ -223,20 +224,18 @@ class EasyReconcileBase(orm.AbstractModel):
# it will do a full reconcile instead of a partial reconcile
# and make a write-off for exchange
if sum_credit > sum_debit:
- writeoff_account_id = rec.income_exchange_account_id.id
+ writeoff_account_id = self.income_exchange_account_id.id
else:
- writeoff_account_id = rec.expense_exchange_account_id.id
- period_id = self.pool['account.period'].find(
- cr, uid, dt=date, context=context)[0]
- if rec.analytic_account_id:
- rec_ctx['analytic_id'] = rec.analytic_account_id.id
- ml_obj.reconcile_partial(
- cr, uid,
- line_ids,
+ writeoff_account_id = self.expense_exchange_account_id.id
+ period_id = self.env['account.period'].find(dt=date)[0]
+ if self.analytic_account_id:
+ rec_ctx['analytic_id'] = self.analytic_account_id.id
+ 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=rec.journal_id.id,
- context=rec_ctx)
+ 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
new file mode 100644
index 00000000..7a7a1bf2
--- /dev/null
+++ b/account_easy_reconcile/easy_reconcile.py
@@ -0,0 +1,379 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright 2012-2013, 2015 Camptocamp SA (Guewen Baconnier, Damien Crier)
+# Copyright (C) 2010 Sébastien Beau
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from datetime import datetime
+from openerp import models, api, fields, _
+from openerp.exceptions import Warning
+from openerp import sql_db
+
+import logging
+_logger = logging.getLogger(__name__)
+
+
+class EasyReconcileOptions(models.AbstractModel):
+ """Options of a reconciliation profile
+
+ Columns shared by the configuration of methods
+ and by the reconciliation wizards.
+ This allows decoupling of the methods and the
+ wizards and allows to launch the wizards alone
+ """
+
+ _name = 'easy.reconcile.options'
+
+ @api.model
+ def _get_rec_base_date(self):
+ return [
+ ('end_period_last_credit', 'End of period of most recent credit'),
+ ('newest', 'Most recent move line'),
+ ('actual', 'Today'),
+ ('end_period', 'End of period of most recent move line'),
+ ('newest_credit', 'Date of most recent credit'),
+ ('newest_debit', 'Date of most recent debit')
+ ]
+
+ write_off = fields.Float('Write off allowed', default=0.)
+ account_lost_id = fields.Many2one('account.account',
+ string="Account Lost")
+ account_profit_id = fields.Many2one('account.account',
+ string="Account Profit")
+ journal_id = fields.Many2one('account.journal',
+ string="Journal")
+ date_base_on = fields.Selection('_get_rec_base_date',
+ required=True,
+ string='Date of reconciliation',
+ default='end_period_last_credit')
+ filter = fields.Char(string='Filter')
+ analytic_account_id = fields.Many2one('account.analytic.account',
+ string='Analytic_account',
+ help="Analytic account "
+ "for the write-off")
+ income_exchange_account_id = fields.Many2one('account.account',
+ string='Gain Exchange '
+ 'Rate Account')
+ expense_exchange_account_id = fields.Many2one('account.account',
+ string='Loss Exchange '
+ 'Rate Account')
+
+
+class AccountEasyReconcileMethod(models.Model):
+ _name = 'account.easy.reconcile.method'
+ _description = 'reconcile method for account_easy_reconcile'
+ _inherit = 'easy.reconcile.options'
+ _order = 'sequence'
+
+ @api.model
+ def _get_all_rec_method(self):
+ return [
+ ('easy.reconcile.simple.name', 'Simple. Amount and Name'),
+ ('easy.reconcile.simple.partner', 'Simple. Amount and Partner'),
+ ('easy.reconcile.simple.reference',
+ 'Simple. Amount and Reference'),
+ ]
+
+ @api.model
+ def _get_rec_method(self):
+ return self._get_all_rec_method()
+
+ name = fields.Selection('_get_rec_method', string='Type', required=True)
+ sequence = fields.Integer(string='Sequence',
+ default=1,
+ required=True,
+ help="The sequence field is used to order "
+ "the reconcile method"
+ )
+ task_id = fields.Many2one('account.easy.reconcile',
+ string='Task',
+ required=True,
+ ondelete='cascade'
+ )
+ company_id = fields.Many2one('res.company',
+ string='Company',
+ related="task_id.company_id",
+ store=True,
+ readonly=True
+ )
+
+
+class AccountEasyReconcile(models.Model):
+
+ _name = 'account.easy.reconcile'
+ _inherit = ['mail.thread']
+ _description = 'account easy reconcile'
+
+ @api.one
+ @api.depends('account')
+ def _get_total_unrec(self):
+ obj_move_line = self.env['account.move.line']
+ 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 = obj_move_line.search_count(
+ [('account_id', '=', self.account.id),
+ ('reconcile_id', '=', False),
+ ('reconcile_partial_id', '!=', False)],
+ )
+
+ @api.one
+ @api.depends('history_ids')
+ def _last_history(self):
+ # do a search() for retrieving the latest history line,
+ # as a read() will badly split the list of ids with 'date desc'
+ # and return the wrong result.
+ history_obj = self.env['easy.reconcile.history']
+ last_history_rs = history_obj.search(
+ [('easy_reconcile_id', '=', self.id)],
+ limit=1, order='date desc'
+ )
+ self.last_history = last_history_rs or False
+
+ name = fields.Char(string='Name', required=True)
+ account = fields.Many2one('account.account',
+ string='Account',
+ required=True,
+ )
+ reconcile_method = fields.One2many('account.easy.reconcile.method',
+ 'task_id',
+ string='Method'
+ )
+ unreconciled_count = fields.Integer(string='Unreconciled Items',
+ compute='_get_total_unrec'
+ )
+ reconciled_partial_count = fields.Integer(
+ string='Partially Reconciled Items',
+ compute='_get_partial_rec'
+ )
+ history_ids = fields.One2many('easy.reconcile.history',
+ 'easy_reconcile_id',
+ string='History',
+ readonly=True
+ )
+ last_history = fields.Many2one('easy.reconcile.history',
+ string='Last history', readonly=True,
+ compute='_last_history',
+ )
+ company_id = fields.Many2one('res.company', string='Company')
+
+ @api.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.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.id),
+ 'expense_exchange_account_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}
+
+ @api.multi
+ def run_reconcile(self):
+ def find_reconcile_ids(fieldname, move_line_ids):
+ if not move_line_ids:
+ return []
+ sql = ("SELECT DISTINCT " + fieldname +
+ " FROM account_move_line "
+ " WHERE id in %s "
+ " AND " + fieldname + " IS NOT NULL")
+ self.env.cr.execute(sql, (tuple(move_line_ids),))
+ res = self.env.cr.fetchall()
+ return [row[0] for row in res]
+
+ # we use a new cursor to be able to commit the reconciliation
+ # often. We have to create it here and not later to avoid problems
+ # where the new cursor sees the lines as reconciles but the old one
+ # does not.
+
+ for rec in self:
+ ctx = self.env.context.copy()
+ ctx['commit_every'] = (
+ rec.account.company_id.reconciliation_commit_every
+ )
+ if ctx['commit_every']:
+ new_cr = sql_db.db_connect(self.env.cr.dbname).cursor()
+ else:
+ new_cr = self.env.cr
+
+ try:
+ all_ml_rec_ids = []
+ all_ml_partial_ids = []
+
+ for method in rec.reconcile_method:
+ rec_model = self.env[method.name]
+ auto_rec_id = rec_model.create(
+ self._prepare_run_transient(method)
+ )
+
+ ml_rec_ids, ml_partial_ids = (
+ auto_rec_id.automatic_reconcile()
+ )
+
+ all_ml_rec_ids += ml_rec_ids
+ all_ml_partial_ids += ml_partial_ids
+
+ reconcile_ids = find_reconcile_ids(
+ 'reconcile_id',
+ all_ml_rec_ids
+ )
+ partial_ids = find_reconcile_ids(
+ 'reconcile_partial_id',
+ all_ml_partial_ids
+ )
+ self.env['easy.reconcile.history'].create(
+ {
+ 'easy_reconcile_id': rec.id,
+ 'date': fields.Datetime.now(),
+ 'reconcile_ids': [
+ (4, rid) for rid in reconcile_ids
+ ],
+ 'reconcile_partial_ids': [
+ (4, rid) for rid in partial_ids
+ ],
+ })
+ except Exception as e:
+ # In case of error, we log it in the mail thread, log the
+ # stack trace and create an empty history line; otherwise,
+ # the cron will just loop on this reconcile task.
+ _logger.exception(
+ "The reconcile task %s had an exception: %s",
+ rec.name, e.message
+ )
+ message = _("There was an error during reconciliation : %s") \
+ % e.message
+ rec.message_post(body=message)
+ self.env['easy.reconcile.history'].create(
+ {
+ 'easy_reconcile_id': rec.id,
+ 'date': fields.Datetime.now(),
+ 'reconcile_ids': [],
+ 'reconcile_partial_ids': [],
+ }
+ )
+ finally:
+ if ctx['commit_every']:
+ new_cr.commit()
+ new_cr.close()
+
+ return True
+
+ @api.multi
+ def _no_history(self):
+ """ Raise an `orm.except_orm` error, supposed to
+ be called when there is no history on the reconciliation
+ task.
+ """
+ raise Warning(
+ _('There is no history of reconciled '
+ 'items on the task: %s.') % self.name
+ )
+
+ @api.model
+ def _open_move_line_list(self, move_line_ids, name):
+ return {
+ 'name': name,
+ 'view_mode': 'tree,form',
+ 'view_id': False,
+ 'view_type': 'form',
+ 'res_model': 'account.move.line',
+ 'type': 'ir.actions.act_window',
+ 'nodestroy': True,
+ 'target': 'current',
+ 'domain': unicode([('id', 'in', move_line_ids)]),
+ }
+
+ @api.multi
+ def open_unreconcile(self):
+ """ Open the view of move line with the unreconciled move lines"""
+ self.ensure_one()
+ obj_move_line = self.env['account.move.line']
+ 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(lines.ids or [], name)
+
+ @api.multi
+ def open_partial_reconcile(self):
+ """ Open the view of move line with the partially
+ reconciled move lines"""
+ self.ensure_one()
+ obj_move_line = self.env['account.move.line']
+ 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(lines.ids or [], name)
+
+ @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 not self.last_history:
+ self._no_history()
+ return self.last_history.open_reconcile()
+
+ @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 not self.last_history:
+ self._no_history()
+ return self.last_history.open_partial()
+
+ @api.model
+ def run_scheduler(self, run_all=None):
+ """ Launch the reconcile with the oldest run
+ This function is mostly here to be used with cron task
+
+ :param run_all: if set it will ingore lookup and launch
+ all reconciliation
+ :returns: True in case of success or raises an exception
+
+ """
+ def _get_date(reconcile):
+ if reconcile.last_history.date:
+ return fields.Datetime.from_string(reconcile.last_history.date)
+ else:
+ return datetime.min
+
+ reconciles = self.search([])
+ assert reconciles.ids, "No easy reconcile available"
+ if run_all:
+ reconciles.run_reconcile()
+ return True
+ reconciles.sorted(key=_get_date)
+ older = reconciles[0]
+ older.run_reconcile()
+ return True
diff --git a/__unported__/account_easy_reconcile/easy_reconcile.xml b/account_easy_reconcile/easy_reconcile.xml
similarity index 97%
rename from __unported__/account_easy_reconcile/easy_reconcile.xml
rename to account_easy_reconcile/easy_reconcile.xml
index 076bd3b3..7de62cbc 100644
--- a/__unported__/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
new file mode 100644
index 00000000..58904b3e
--- /dev/null
+++ b/account_easy_reconcile/easy_reconcile_history.py
@@ -0,0 +1,139 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Guewen Baconnier, Damien Crier
+# Copyright 2012, 2015 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from openerp import models, api, fields, _
+
+
+class EasyReconcileHistory(models.Model):
+ """ Store an history of the runs per profile
+ Each history stores the list of reconciliations done"""
+
+ _name = 'easy.reconcile.history'
+ _rec_name = 'easy_reconcile_id'
+ _order = 'date DESC'
+
+ @api.one
+ @api.depends('reconcile_ids', 'reconcile_partial_ids')
+ def _get_reconcile_line_ids(self):
+ move_line_ids = []
+ for reconcile in self.reconcile_ids:
+ move_lines = reconcile.mapped('line_id')
+ move_line_ids.extend(move_lines.ids)
+ self.reconcile_line_ids = move_line_ids
+
+ move_line_ids2 = []
+ for reconcile2 in self.reconcile_partial_ids:
+ move_lines2 = reconcile2.mapped('line_partial_ids')
+ move_line_ids2.extend(move_lines2.ids)
+ self.partial_line_ids = move_line_ids2
+
+ easy_reconcile_id = fields.Many2one(
+ 'account.easy.reconcile',
+ string='Reconcile Profile',
+ readonly=True
+ )
+ date = fields.Datetime(string='Run date', readonly=True, required=True)
+ reconcile_ids = fields.Many2many(
+ comodel_name='account.move.reconcile',
+ relation='account_move_reconcile_history_rel',
+ string='Partial Reconciliations',
+ readonly=True
+ )
+ reconcile_partial_ids = fields.Many2many(
+ comodel_name='account.move.reconcile',
+ relation='account_move_reconcile_history_partial_rel',
+ string='Partial Reconciliations',
+ readonly=True
+ )
+ reconcile_line_ids = fields.Many2many(
+ comodel_name='account.move.line',
+ relation='account_move_line_history_rel',
+ string='Reconciled Items',
+ compute='_get_reconcile_line_ids'
+ )
+ partial_line_ids = fields.Many2many(
+ comodel_name='account.move.line',
+ relation='account_move_line_history_partial_rel',
+ string='Partially Reconciled Items',
+ compute='_get_reconcile_line_ids'
+ )
+ company_id = fields.Many2one(
+ 'res.company',
+ string='Company',
+ store=True,
+ readonly=True,
+ related='easy_reconcile_id.company_id'
+ )
+
+ @api.multi
+ def _open_move_lines(self, rec_type='full'):
+ """ For an history record, open the view of move line with
+ the reconciled or partially reconciled move lines
+
+ :param history_id: id of the history
+ :param rec_type: 'full' or 'partial'
+ :return: action to open the move lines
+ """
+ assert rec_type in ('full', 'partial'), \
+ "rec_type must be 'full' or 'partial'"
+ move_line_ids = []
+ if rec_type == 'full':
+ move_line_ids = self.mapped('reconcile_ids.line_id').ids
+ name = _('Reconciliations')
+ else:
+ move_line_ids = self.mapped(
+ 'reconcile_partial_ids.line_partial_ids').ids
+ name = _('Partial Reconciliations')
+ return {
+ 'name': name,
+ 'view_mode': 'tree,form',
+ 'view_id': False,
+ 'view_type': 'form',
+ 'res_model': 'account.move.line',
+ 'type': 'ir.actions.act_window',
+ 'nodestroy': True,
+ 'target': 'current',
+ '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
+
+ :param history_ids: id of the record as int or long
+ Accept a list with 1 id too to be
+ used from the client.
+ """
+ self.ensure_one()
+ return self._open_move_lines(rec_type='full')
+
+ @api.multi
+ def open_partial(self):
+ """ For an history record, open the view of move line
+ with the partially reconciled move lines
+
+ :param history_ids: id of the record as int or long
+ Accept a list with 1 id too to be
+ used from the client.
+ """
+ self.ensure_one()
+ return self._open_move_lines(rec_type='partial')
diff --git a/__unported__/account_easy_reconcile/easy_reconcile_history_view.xml b/account_easy_reconcile/easy_reconcile_history_view.xml
similarity index 100%
rename from __unported__/account_easy_reconcile/easy_reconcile_history_view.xml
rename to account_easy_reconcile/easy_reconcile_history_view.xml
diff --git a/__unported__/account_easy_reconcile/i18n/account_easy_reconcile.pot b/account_easy_reconcile/i18n/account_easy_reconcile.pot
similarity index 54%
rename from __unported__/account_easy_reconcile/i18n/account_easy_reconcile.pot
rename to account_easy_reconcile/i18n/account_easy_reconcile.pot
index 598b81ea..76d49a52 100644
--- a/__unported__/account_easy_reconcile/i18n/account_easy_reconcile.pot
+++ b/account_easy_reconcile/i18n/account_easy_reconcile.pot
@@ -1,13 +1,13 @@
-# Translation of OpenERP Server.
+# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_easy_reconcile
#
msgid ""
msgstr ""
-"Project-Id-Version: OpenERP Server 7.0\n"
+"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-01-21 11:55+0000\n"
-"PO-Revision-Date: 2014-01-21 11:55+0000\n"
+"POT-Creation-Date: 2015-06-12 14:08+0000\n"
+"PO-Revision-Date: 2015-06-12 14:08+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@@ -16,38 +16,8 @@ msgstr ""
"Plural-Forms: \n"
#. module: account_easy_reconcile
-#: code:addons/account_easy_reconcile/easy_reconcile_history.py:108
-#: view:easy.reconcile.history:0
-#: field:easy.reconcile.history,reconcile_ids:0
-#, python-format
-msgid "Reconciliations"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-#: view:easy.reconcile.history:0
-msgid "Automatic Easy Reconcile History"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Information"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-#: view:easy.reconcile.history:0
-msgid "Go to partially reconciled items"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: help:account.easy.reconcile.method,sequence:0
-msgid "The sequence field is used to order the reconcile method"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_history
-msgid "easy.reconcile.history"
+#: view:easy.reconcile.history:account_easy_reconcile.view_easy_reconcile_history_search
+msgid "7 Days"
msgstr ""
#. module: account_easy_reconcile
@@ -63,161 +33,6 @@ msgid "\n"
" "
msgstr ""
-#. module: account_easy_reconcile
-#: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_options
-msgid "easy.reconcile.options"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:easy.reconcile.history:0
-msgid "Group By..."
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:account.easy.reconcile,unreconciled_count:0
-msgid "Unreconciled Items"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_base
-msgid "easy.reconcile.base"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:easy.reconcile.history,reconcile_line_ids:0
-msgid "Reconciled Items"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:account.easy.reconcile,reconcile_method:0
-msgid "Method"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:easy.reconcile.history:0
-msgid "7 Days"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: model:ir.actions.act_window,name:account_easy_reconcile.action_easy_reconcile_history
-msgid "Easy Automatic Reconcile History"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:easy.reconcile.history,date:0
-msgid "Run date"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Match one debit line vs one credit line. Do not allow partial reconciliation. The lines should have the same amount (with the write-off) and the same reference to be reconciled."
-msgstr ""
-
-#. module: account_easy_reconcile
-#: model:ir.actions.act_window,name:account_easy_reconcile.act_easy_reconcile_to_history
-msgid "History Details"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Display items reconciled on the last run"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:account.easy.reconcile.method,name:0
-msgid "Type"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:account.easy.reconcile,company_id:0
-#: field:account.easy.reconcile.method,company_id:0
-#: field:easy.reconcile.history,company_id:0
-msgid "Company"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:account.easy.reconcile.method,account_profit_id:0
-#: field:easy.reconcile.base,account_profit_id:0
-#: field:easy.reconcile.options,account_profit_id:0
-#: field:easy.reconcile.simple,account_profit_id:0
-#: field:easy.reconcile.simple.name,account_profit_id:0
-#: field:easy.reconcile.simple.partner,account_profit_id:0
-#: field:easy.reconcile.simple.reference,account_profit_id:0
-msgid "Account Profit"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:easy.reconcile.history:0
-msgid "Todays' Reconcilations"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Simple. Amount and Name"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:easy.reconcile.base,partner_ids:0
-#: field:easy.reconcile.simple,partner_ids:0
-#: field:easy.reconcile.simple.name,partner_ids:0
-#: field:easy.reconcile.simple.partner,partner_ids:0
-#: field:easy.reconcile.simple.reference,partner_ids:0
-msgid "Restrict on partners"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: model:ir.actions.act_window,name:account_easy_reconcile.action_account_easy_reconcile
-#: model:ir.ui.menu,name:account_easy_reconcile.menu_easy_reconcile
-msgid "Easy Automatic Reconcile"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:easy.reconcile.history:0
-msgid "Today"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:easy.reconcile.history:0
-msgid "Date"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:account.easy.reconcile,last_history:0
-msgid "Last History"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Configuration"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:account.easy.reconcile,reconciled_partial_count:0
-#: field:easy.reconcile.history,partial_line_ids:0
-msgid "Partially Reconciled Items"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple_partner
-msgid "easy.reconcile.simple.partner"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:account.easy.reconcile.method,write_off:0
-#: field:easy.reconcile.base,write_off:0
-#: field:easy.reconcile.options,write_off:0
-#: field:easy.reconcile.simple,write_off:0
-#: field:easy.reconcile.simple.name,write_off:0
-#: field:easy.reconcile.simple.partner,write_off:0
-#: field:easy.reconcile.simple.reference,write_off:0
-msgid "Write off allowed"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Automatic Easy Reconcile"
-msgstr ""
-
#. module: account_easy_reconcile
#: field:account.easy.reconcile,account:0
#: field:easy.reconcile.base,account_id:0
@@ -228,79 +43,6 @@ msgstr ""
msgid "Account"
msgstr ""
-#. module: account_easy_reconcile
-#: field:account.easy.reconcile.method,task_id:0
-msgid "Task"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:account.easy.reconcile,name:0
-msgid "Name"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Simple. Amount and Partner"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Start Auto Reconcilation"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple_name
-msgid "easy.reconcile.simple.name"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:account.easy.reconcile.method,filter:0
-#: field:easy.reconcile.base,filter:0
-#: field:easy.reconcile.options,filter:0
-#: field:easy.reconcile.simple,filter:0
-#: field:easy.reconcile.simple.name,filter:0
-#: field:easy.reconcile.simple.partner,filter:0
-#: field:easy.reconcile.simple.reference,filter:0
-msgid "Filter"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Match one debit line vs one credit line. Do not allow partial reconciliation. The lines should have the same amount (with the write-off) and the same partner to be reconciled."
-msgstr ""
-
-#. module: account_easy_reconcile
-#: field:easy.reconcile.history,easy_reconcile_id:0
-msgid "Reconcile Profile"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: model:ir.model,name:account_easy_reconcile.model_account_easy_reconcile_method
-msgid "reconcile method for account_easy_reconcile"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Start Auto Reconciliation"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: code:addons/account_easy_reconcile/easy_reconcile.py:257
-#, python-format
-msgid "Error"
-msgstr ""
-
-#. module: account_easy_reconcile
-#: code:addons/account_easy_reconcile/easy_reconcile.py:258
-#, python-format
-msgid "There is no history of reconciled items on the task: %s."
-msgstr ""
-
-#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Match one debit line vs one credit line. Do not allow partial reconciliation. The lines should have the same amount (with the write-off) and the same name to be reconciled."
-msgstr ""
-
#. module: account_easy_reconcile
#: field:account.easy.reconcile.method,account_lost_id:0
#: field:easy.reconcile.base,account_lost_id:0
@@ -313,55 +55,98 @@ msgid "Account Lost"
msgstr ""
#. module: account_easy_reconcile
-#: view:easy.reconcile.history:0
-msgid "Reconciliation Profile"
+#: field:account.easy.reconcile.method,account_profit_id:0
+#: field:easy.reconcile.base,account_profit_id:0
+#: field:easy.reconcile.options,account_profit_id:0
+#: field:easy.reconcile.simple,account_profit_id:0
+#: field:easy.reconcile.simple.name,account_profit_id:0
+#: field:easy.reconcile.simple.partner,account_profit_id:0
+#: field:easy.reconcile.simple.reference,account_profit_id:0
+msgid "Account Profit"
msgstr ""
#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-#: field:account.easy.reconcile,history_ids:0
-msgid "History"
+#: help:account.easy.reconcile.method,analytic_account_id:0
+#: help:easy.reconcile.base,analytic_account_id:0
+#: help:easy.reconcile.options,analytic_account_id:0
+#: help:easy.reconcile.simple,analytic_account_id:0
+#: help:easy.reconcile.simple.name,analytic_account_id:0
+#: help:easy.reconcile.simple.partner,analytic_account_id:0
+#: help:easy.reconcile.simple.reference,analytic_account_id:0
+msgid "Analytic accountfor the write-off"
msgstr ""
#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-#: view:easy.reconcile.history:0
-msgid "Go to reconciled items"
+#: field:account.easy.reconcile.method,analytic_account_id:0
+#: field:easy.reconcile.base,analytic_account_id:0
+#: field:easy.reconcile.options,analytic_account_id:0
+#: field:easy.reconcile.simple,analytic_account_id:0
+#: field:easy.reconcile.simple.name,analytic_account_id:0
+#: field:easy.reconcile.simple.partner,analytic_account_id:0
+#: field:easy.reconcile.simple.reference,analytic_account_id:0
+msgid "Analytic_account"
msgstr ""
#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Profile Information"
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_tree
+msgid "Automatic Easy Reconcile"
msgstr ""
#. module: account_easy_reconcile
-#: view:account.easy.reconcile.method:0
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+#: view:easy.reconcile.history:account_easy_reconcile.easy_reconcile_history_form
+#: view:easy.reconcile.history:account_easy_reconcile.easy_reconcile_history_tree
+#: view:easy.reconcile.history:account_easy_reconcile.view_easy_reconcile_history_search
+msgid "Automatic Easy Reconcile History"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile.method:account_easy_reconcile.account_easy_reconcile_method_form
+#: view:account.easy.reconcile.method:account_easy_reconcile.account_easy_reconcile_method_tree
msgid "Automatic Easy Reconcile Method"
msgstr ""
#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Simple. Amount and Reference"
+#: model:ir.model,name:account_easy_reconcile.model_res_company
+msgid "Companies"
msgstr ""
#. module: account_easy_reconcile
-#: view:account.easy.reconcile:0
-msgid "Display items partially reconciled on the last run"
+#: field:account.easy.reconcile,company_id:0
+#: field:account.easy.reconcile.method,company_id:0
+#: field:easy.reconcile.history,company_id:0
+msgid "Company"
msgstr ""
#. module: account_easy_reconcile
-#: field:account.easy.reconcile.method,sequence:0
-msgid "Sequence"
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Configuration"
msgstr ""
#. module: account_easy_reconcile
-#: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple
-msgid "easy.reconcile.simple"
+#: field:account.easy.reconcile,create_uid:0
+#: field:account.easy.reconcile.method,create_uid:0
+#: field:easy.reconcile.history,create_uid:0
+#: field:easy.reconcile.simple.name,create_uid:0
+#: field:easy.reconcile.simple.partner,create_uid:0
+#: field:easy.reconcile.simple.reference,create_uid:0
+msgid "Created by"
msgstr ""
#. module: account_easy_reconcile
-#: view:easy.reconcile.history:0
-msgid "Reconciliations of last 7 days"
+#: field:account.easy.reconcile,create_date:0
+#: field:account.easy.reconcile.method,create_date:0
+#: field:easy.reconcile.history,create_date:0
+#: field:easy.reconcile.simple.name,create_date:0
+#: field:easy.reconcile.simple.partner,create_date:0
+#: field:easy.reconcile.simple.reference,create_date:0
+msgid "Created on"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:easy.reconcile.history:account_easy_reconcile.view_easy_reconcile_history_search
+msgid "Date"
msgstr ""
#. module: account_easy_reconcile
@@ -376,11 +161,142 @@ msgid "Date of reconciliation"
msgstr ""
#. module: account_easy_reconcile
-#: code:addons/account_easy_reconcile/easy_reconcile_history.py:111
-#: view:easy.reconcile.history:0
-#: field:easy.reconcile.history,reconcile_partial_ids:0
+#: help:account.easy.reconcile,message_last_post:0
+msgid "Date of the last message posted on the record."
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_tree
+msgid "Display items partially reconciled on the last run"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_tree
+msgid "Display items reconciled on the last run"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: model:ir.actions.act_window,name:account_easy_reconcile.action_account_easy_reconcile
+#: model:ir.ui.menu,name:account_easy_reconcile.menu_easy_reconcile
+msgid "Easy Automatic Reconcile"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: model:ir.actions.act_window,name:account_easy_reconcile.action_easy_reconcile_history
+msgid "Easy Automatic Reconcile History"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: code:addons/account_easy_reconcile/easy_reconcile.py:329
#, python-format
-msgid "Partial Reconciliations"
+msgid "Error"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile.method,filter:0
+#: field:easy.reconcile.base,filter:0
+#: field:easy.reconcile.options,filter:0
+#: field:easy.reconcile.simple,filter:0
+#: field:easy.reconcile.simple.name,filter:0
+#: field:easy.reconcile.simple.partner,filter:0
+#: field:easy.reconcile.simple.reference,filter:0
+msgid "Filter"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile,message_follower_ids:0
+msgid "Followers"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile.method,income_exchange_account_id:0
+#: field:easy.reconcile.base,income_exchange_account_id:0
+#: field:easy.reconcile.options,income_exchange_account_id:0
+#: field:easy.reconcile.simple,income_exchange_account_id:0
+#: field:easy.reconcile.simple.name,income_exchange_account_id:0
+#: field:easy.reconcile.simple.partner,income_exchange_account_id:0
+#: field:easy.reconcile.simple.reference,income_exchange_account_id:0
+msgid "Gain ExchangeRate Account"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Go to partial reconciled items"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+#: view:easy.reconcile.history:account_easy_reconcile.easy_reconcile_history_form
+#: view:easy.reconcile.history:account_easy_reconcile.easy_reconcile_history_tree
+msgid "Go to partially reconciled items"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+#: view:easy.reconcile.history:account_easy_reconcile.easy_reconcile_history_form
+#: view:easy.reconcile.history:account_easy_reconcile.easy_reconcile_history_tree
+msgid "Go to reconciled items"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Go to unreconciled items"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:easy.reconcile.history:account_easy_reconcile.view_easy_reconcile_history_search
+msgid "Group By..."
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+#: field:account.easy.reconcile,history_ids:0
+msgid "History"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: model:ir.actions.act_window,name:account_easy_reconcile.act_easy_reconcile_to_history
+msgid "History Details"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: help:account.easy.reconcile,message_summary:0
+msgid "Holds the Chatter summary (number of messages, ...). This summary is directly in html format in order to be inserted in kanban views."
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:res.company,reconciliation_commit_every:0
+msgid "How often to commit when performing automaticreconciliation."
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile,id:0
+#: field:account.easy.reconcile.method,id:0
+#: field:easy.reconcile.base,id:0
+#: field:easy.reconcile.history,id:0
+#: field:easy.reconcile.options,id:0
+#: field:easy.reconcile.simple,id:0
+#: field:easy.reconcile.simple.name,id:0
+#: field:easy.reconcile.simple.partner,id:0
+#: field:easy.reconcile.simple.reference,id:0
+msgid "ID"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: help:account.easy.reconcile,message_unread:0
+msgid "If checked new messages require your attention."
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Information"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile,message_is_follower:0
+msgid "Is a Follower"
msgstr ""
#. module: account_easy_reconcile
@@ -395,13 +311,33 @@ msgid "Journal"
msgstr ""
#. module: account_easy_reconcile
-#: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple_reference
-msgid "easy.reconcile.simple.reference"
+#: field:account.easy.reconcile,message_last_post:0
+msgid "Last Message Date"
msgstr ""
#. module: account_easy_reconcile
-#: model:ir.model,name:account_easy_reconcile.model_account_easy_reconcile
-msgid "account easy reconcile"
+#: field:account.easy.reconcile,write_uid:0
+#: field:account.easy.reconcile.method,write_uid:0
+#: field:easy.reconcile.history,write_uid:0
+#: field:easy.reconcile.simple.name,write_uid:0
+#: field:easy.reconcile.simple.partner,write_uid:0
+#: field:easy.reconcile.simple.reference,write_uid:0
+msgid "Last Updated by"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile,write_date:0
+#: field:account.easy.reconcile.method,write_date:0
+#: field:easy.reconcile.history,write_date:0
+#: field:easy.reconcile.simple.name,write_date:0
+#: field:easy.reconcile.simple.partner,write_date:0
+#: field:easy.reconcile.simple.reference,write_date:0
+msgid "Last Updated on"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: help:res.company,reconciliation_commit_every:0
+msgid "Leave zero to commit only at the end of the process."
msgstr ""
#. module: account_easy_reconcile
@@ -412,16 +348,220 @@ msgstr ""
#: field:easy.reconcile.simple.name,expense_exchange_account_id:0
#: field:easy.reconcile.simple.partner,expense_exchange_account_id:0
#: field:easy.reconcile.simple.reference,expense_exchange_account_id:0
-msgid "Loss Exchange Rate Account"
+msgid "Loss ExchangeRate Account"
msgstr ""
#. module: account_easy_reconcile
-#: field:account.easy.reconcile.method,income_exchange_account_id:0
-#: field:easy.reconcile.base,income_exchange_account_id:0
-#: field:easy.reconcile.options,income_exchange_account_id:0
-#: field:easy.reconcile.simple,income_exchange_account_id:0
-#: field:easy.reconcile.simple.name,income_exchange_account_id:0
-#: field:easy.reconcile.simple.partner,income_exchange_account_id:0
-#: field:easy.reconcile.simple.reference,income_exchange_account_id:0
-msgid "Gain Exchange Rate Account"
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Match one debit line vs one credit line. Do not allow partial reconciliation. The lines should have the same amount (with the write-off) and the same name to be reconciled."
msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Match one debit line vs one credit line. Do not allow partial reconciliation. The lines should have the same amount (with the write-off) and the same partner to be reconciled."
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Match one debit line vs one credit line. Do not allow partial reconciliation. The lines should have the same amount (with the write-off) and the same reference to be reconciled."
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile,message_ids:0
+msgid "Messages"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: help:account.easy.reconcile,message_ids:0
+msgid "Messages and communication history"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile,reconcile_method:0
+msgid "Method"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile,name:0
+msgid "Name"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.config.settings:account_easy_reconcile.view_account_config
+msgid "Options"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: code:addons/account_easy_reconcile/easy_reconcile_history.py:108
+#: view:easy.reconcile.history:account_easy_reconcile.easy_reconcile_history_form
+#: field:easy.reconcile.history,reconcile_ids:0
+#: field:easy.reconcile.history,reconcile_partial_ids:0
+#, python-format
+msgid "Partial Reconciliations"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: code:addons/account_easy_reconcile/easy_reconcile.py:368
+#, python-format
+msgid "Partial reconciled items"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:easy.reconcile.history,partial_line_ids:0
+msgid "Partially Reconciled Items"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Profile Information"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:easy.reconcile.history,easy_reconcile_id:0
+msgid "Reconcile Profile"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:easy.reconcile.history,reconcile_line_ids:0
+msgid "Reconciled Items"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.config.settings:account_easy_reconcile.view_account_config
+msgid "Reconciliation"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:easy.reconcile.history:account_easy_reconcile.view_easy_reconcile_history_search
+msgid "Reconciliation Profile"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: code:addons/account_easy_reconcile/easy_reconcile_history.py:105
+#: view:easy.reconcile.history:account_easy_reconcile.easy_reconcile_history_form
+#, python-format
+msgid "Reconciliations"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:easy.reconcile.history:account_easy_reconcile.view_easy_reconcile_history_search
+msgid "Reconciliations of last 7 days"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:easy.reconcile.base,partner_ids:0
+#: field:easy.reconcile.simple,partner_ids:0
+#: field:easy.reconcile.simple.name,partner_ids:0
+#: field:easy.reconcile.simple.partner,partner_ids:0
+#: field:easy.reconcile.simple.reference,partner_ids:0
+msgid "Restrict on partners"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:easy.reconcile.history,date:0
+msgid "Run date"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile.method,sequence:0
+msgid "Sequence"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Simple. Amount and Name"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Simple. Amount and Partner"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Simple. Amount and Reference"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_tree
+msgid "Start Auto Reconcilation"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.easy.reconcile:account_easy_reconcile.account_easy_reconcile_form
+msgid "Start Auto Reconciliation"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile,message_summary:0
+msgid "Summary"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile.method,task_id:0
+msgid "Task"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: help:account.easy.reconcile.method,sequence:0
+msgid "The sequence field is used to order the reconcile method"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: code:addons/account_easy_reconcile/easy_reconcile.py:330
+#, python-format
+msgid "There is no history of reconciled items on the task: %s."
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:easy.reconcile.history:account_easy_reconcile.view_easy_reconcile_history_search
+msgid "Today"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:easy.reconcile.history:account_easy_reconcile.view_easy_reconcile_history_search
+msgid "Todays' Reconcilations"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile.method,name:0
+msgid "Type"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile,message_unread:0
+msgid "Unread Messages"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: code:addons/account_easy_reconcile/easy_reconcile.py:356
+#, python-format
+msgid "Unreconciled items"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: field:account.easy.reconcile.method,write_off:0
+#: field:easy.reconcile.base,write_off:0
+#: field:easy.reconcile.options,write_off:0
+#: field:easy.reconcile.simple,write_off:0
+#: field:easy.reconcile.simple.name,write_off:0
+#: field:easy.reconcile.simple.partner,write_off:0
+#: field:easy.reconcile.simple.reference,write_off:0
+msgid "Write off allowed"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: model:ir.model,name:account_easy_reconcile.model_account_easy_reconcile
+msgid "account easy reconcile"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: view:account.config.settings:account_easy_reconcile.view_account_config
+msgid "eInvoicing & Payments"
+msgstr ""
+
+#. module: account_easy_reconcile
+#: model:ir.model,name:account_easy_reconcile.model_account_easy_reconcile_method
+msgid "reconcile method for account_easy_reconcile"
+msgstr ""
+
diff --git a/__unported__/account_easy_reconcile/i18n/es.po b/account_easy_reconcile/i18n/es.po
similarity index 100%
rename from __unported__/account_easy_reconcile/i18n/es.po
rename to account_easy_reconcile/i18n/es.po
diff --git a/__unported__/account_easy_reconcile/i18n/fr.po b/account_easy_reconcile/i18n/fr.po
similarity index 100%
rename from __unported__/account_easy_reconcile/i18n/fr.po
rename to account_easy_reconcile/i18n/fr.po
diff --git a/__unported__/account_easy_reconcile/res_config.py b/account_easy_reconcile/res_config.py
similarity index 53%
rename from __unported__/account_easy_reconcile/res_config.py
rename to account_easy_reconcile/res_config.py
index cb827ab3..090810d3 100644
--- a/__unported__/account_easy_reconcile/res_config.py
+++ b/account_easy_reconcile/res_config.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Author: Leonardo Pistone
-# Copyright 2014 Camptocamp SA
+# Author: Leonardo Pistone, Damien Crier
+# Copyright 2014, 2015 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -19,41 +19,39 @@
#
##############################################################################
-from openerp.osv import orm, fields
+from openerp import models, api, fields
-class AccountConfigSettings(orm.TransientModel):
+class AccountConfigSettings(models.TransientModel):
_inherit = 'account.config.settings'
- _columns = {
- 'reconciliation_commit_every': fields.related(
- 'company_id',
- 'reconciliation_commit_every',
- type='integer',
- string='How often to commit when performing automatic '
- 'reconciliation.',
- help="""Leave zero to commit only at the end of the process."""),
- }
+ reconciliation_commit_every = fields.Integer(
+ related="company_id.reconciliation_commit_every",
+ string="How often to commit when performing automatic "
+ "reconciliation.",
+ help="Leave zero to commit only at the end of the process."
+ )
- def onchange_company_id(self, cr, uid, ids, company_id, context=None):
- company_obj = self.pool['res.company']
+ @api.multi
+ def onchange_company_id(self, company_id):
result = super(AccountConfigSettings, self).onchange_company_id(
- cr, uid, ids, company_id, context=None)
+ company_id
+ )
if company_id:
- company = company_obj.browse(cr, uid, company_id, context=context)
+ company = self.env['res.company'].browse(company_id)
result['value']['reconciliation_commit_every'] = (
company.reconciliation_commit_every
)
return result
-class Company(orm.Model):
+class Company(models.Model):
_inherit = "res.company"
- _columns = {
- 'reconciliation_commit_every': fields.integer(
- string='How often to commit when performing automatic '
- 'reconciliation.',
- help="""Leave zero to commit only at the end of the process."""),
- }
+
+ reconciliation_commit_every = fields.Integer(
+ string="How often to commit when performing automatic "
+ "reconciliation.",
+ help="Leave zero to commit only at the end of the process."
+ )
diff --git a/__unported__/account_easy_reconcile/res_config_view.xml b/account_easy_reconcile/res_config_view.xml
similarity index 100%
rename from __unported__/account_easy_reconcile/res_config_view.xml
rename to account_easy_reconcile/res_config_view.xml
diff --git a/__unported__/account_easy_reconcile/security/ir.model.access.csv b/account_easy_reconcile/security/ir.model.access.csv
similarity index 100%
rename from __unported__/account_easy_reconcile/security/ir.model.access.csv
rename to account_easy_reconcile/security/ir.model.access.csv
diff --git a/__unported__/account_easy_reconcile/security/ir_rule.xml b/account_easy_reconcile/security/ir_rule.xml
similarity index 100%
rename from __unported__/account_easy_reconcile/security/ir_rule.xml
rename to account_easy_reconcile/security/ir_rule.xml
diff --git a/__unported__/account_easy_reconcile/simple_reconciliation.py b/account_easy_reconcile/simple_reconciliation.py
similarity index 76%
rename from __unported__/account_easy_reconcile/simple_reconciliation.py
rename to account_easy_reconcile/simple_reconciliation.py
index f108ff4f..41943517 100644
--- a/__unported__/account_easy_reconcile/simple_reconciliation.py
+++ b/account_easy_reconcile/simple_reconciliation.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Copyright 2012-2013 Camptocamp SA (Guewen Baconnier)
+# Copyright 2012-2013, 2015 Camptocamp SA (Guewen Baconnier, Damien Crier)
# Copyright (C) 2010 Sébastien Beau
#
# This program is free software: you can redistribute it and/or modify
@@ -19,10 +19,11 @@
#
##############################################################################
-from openerp.osv.orm import AbstractModel, TransientModel
+# from openerp.osv.orm import AbstractModel, TransientModel
+from openerp import models, api
-class EasyReconcileSimple(AbstractModel):
+class EasyReconcileSimple(models.AbstractModel):
_name = 'easy.reconcile.simple'
_inherit = 'easy.reconcile.base'
@@ -30,7 +31,8 @@ class EasyReconcileSimple(AbstractModel):
# field name used as key for matching the move lines
_key_field = None
- def rec_auto_lines_simple(self, cr, uid, rec, lines, context=None):
+ @api.multi
+ def rec_auto_lines_simple(self, lines):
if self._key_field is None:
raise ValueError("_key_field has to be defined")
count = 0
@@ -51,8 +53,9 @@ class EasyReconcileSimple(AbstractModel):
if not check:
continue
reconciled, dummy = self._reconcile_lines(
- cr, uid, rec, [credit_line, debit_line],
- allow_partial=False, context=context)
+ [credit_line, debit_line],
+ allow_partial=False
+ )
if reconciled:
res += [credit_line['id'], debit_line['id']]
del lines[i]
@@ -60,29 +63,30 @@ class EasyReconcileSimple(AbstractModel):
count += 1
return res, [] # empty list for partial, only full rec in "simple" rec
- def _simple_order(self, rec, *args, **kwargs):
+ @api.multi
+ def _simple_order(self, *args, **kwargs):
return "ORDER BY account_move_line.%s" % self._key_field
- def _action_rec(self, cr, uid, rec, context=None):
+ def _action_rec(self):
"""Match only 2 move lines, do not allow partial reconcile"""
- select = self._select(rec)
+ select = self._select()
select += ", account_move_line.%s " % self._key_field
- where, params = self._where(rec)
+ where, params = self._where()
where += " AND account_move_line.%s IS NOT NULL " % self._key_field
- where2, params2 = self._get_filter(cr, uid, rec, context=context)
+ where2, params2 = self._get_filter()
query = ' '.join((
select,
- self._from(rec),
+ self._from(),
where, where2,
- self._simple_order(rec)))
+ self._simple_order()))
- cr.execute(query, params + params2)
- lines = cr.dictfetchall()
- return self.rec_auto_lines_simple(cr, uid, rec, lines, context)
+ self.env.cr.execute(query, params + params2)
+ lines = self.env.cr.dictfetchall()
+ return self.rec_auto_lines_simple(lines)
-class EasyReconcileSimpleName(TransientModel):
+class EasyReconcileSimpleName(models.TransientModel):
_name = 'easy.reconcile.simple.name'
_inherit = 'easy.reconcile.simple'
@@ -91,7 +95,7 @@ class EasyReconcileSimpleName(TransientModel):
_key_field = 'name'
-class EasyReconcileSimplePartner(TransientModel):
+class EasyReconcileSimplePartner(models.TransientModel):
_name = 'easy.reconcile.simple.partner'
_inherit = 'easy.reconcile.simple'
@@ -100,7 +104,7 @@ class EasyReconcileSimplePartner(TransientModel):
_key_field = 'partner_id'
-class EasyReconcileSimpleReference(TransientModel):
+class EasyReconcileSimpleReference(models.TransientModel):
_name = 'easy.reconcile.simple.reference'
_inherit = 'easy.reconcile.simple'
diff --git a/account_easy_reconcile/test/easy_reconcile.yml b/account_easy_reconcile/test/easy_reconcile.yml
new file mode 100644
index 00000000..6142a597
--- /dev/null
+++ b/account_easy_reconcile/test/easy_reconcile.yml
@@ -0,0 +1,116 @@
+-
+ In order to test Confirm Draft Invoice wizard I create an invoice and confirm it with this wizard
+-
+ !record {model: account.invoice, id: account_invoice_state2}:
+ account_id: account.a_recv
+ company_id: base.main_company
+ currency_id: base.EUR
+ invoice_line:
+ - account_id: account.a_sale
+ name: '[PCSC234] PC Assemble SC234'
+ price_unit: 1000.0
+ quantity: 1.0
+ product_id: product.product_product_3
+ uos_id: product.product_uom_unit
+ journal_id: account.bank_journal
+ partner_id: base.res_partner_12
+ reference_type: none
+-
+ I called the "Confirm Draft Invoices" wizard
+-
+ !record {model: account.invoice.confirm, id: account_invoice_confirm_0}:
+ {}
+-
+ I clicked on Confirm Invoices Button
+-
+ !python {model: account.invoice.confirm}: |
+ self.invoice_confirm(cr, uid, [ref("account_invoice_confirm_0")], {"lang": 'en_US',
+ "tz": False, "active_model": "account.invoice", "active_ids": [ref("account_invoice_state2")],
+ "type": "out_invoice", "active_id": ref("account_invoice_state2"), })
+-
+ I check that customer invoice state is "Open"
+-
+ !assert {model: account.invoice, id: account_invoice_state2}:
+ - state == 'open'
+
+
+-
+ In order to test Bank Statement feature of account I create a bank statement line and confirm it and check it's move created
+-
+ I select the period and journal for the bank statement
+-
+ !python {model: account.bank.statement}: |
+ import time
+ journal = self._default_journal_id(cr, uid, {'lang': u'en_US', 'tz': False, 'active_model': 'ir.ui.menu',
+ 'journal_type': 'bank', 'period_id': time.strftime('%m'), 'active_ids': [ref('account.menu_bank_statement_tree')], 'active_id': ref('account.menu_bank_statement_tree')})
+ assert journal, 'Journal has not been selected'
+-
+ I create a bank statement with Opening and Closing balance 0.
+-
+ !record {model: account.bank.statement, id: account_bank_statement_0}:
+ balance_end_real: 0.0
+ balance_start: 0.0
+ date: !eval time.strftime('%Y-%m-%d')
+ journal_id: account.bank_journal
+-
+ I create bank statement line
+-
+ !python {model: account.bank.statement.line}: |
+ vals = {
+ 'amount': 1000.0,
+ 'partner_id': ref('base.res_partner_12'),
+ 'statement_id': ref('account_bank_statement_0'),
+ 'name': 'EXT001'
+ }
+
+ line_id = self.create(cr, uid, vals)
+ assert line_id, "Account bank statement line has not been created"
+
+-
+ We process the reconciliation of the invoice line
+-
+ !python {model: account.bank.statement}: |
+ line_id = None
+ invoice = self.pool.get('account.invoice').browse(cr, uid, ref("account_invoice_state2"))
+ for l in invoice.move_id.line_id:
+ if l.account_id.id == ref('account.a_recv'):
+ line_id = l
+ break
+ statement = self.browse(cr, uid, ref("account_bank_statement_0"))
+ for statement_line in statement.line_ids:
+ self.pool.get('account.bank.statement.line').process_reconciliation(
+ cr, uid, statement_line.id,
+ [
+ {
+ 'counterpart_move_line_id': line_id.id,
+ 'credit': 1000.0,
+ 'debit': 0.0,
+ 'name': line_id.name
+ }
+ ]
+ )
+-
+ We unreconcile previous reconciliation so we can create an easy reconcile record to reconcile invoice
+-
+ !python {model: account.move.line}: |
+ lines_to_unreconcile = self.search(cr, uid, [('reconcile_ref', '!=', False), ('statement_id', '=', ref("account_bank_statement_0"))])
+ self._remove_move_reconcile(cr, uid, lines_to_unreconcile)
+
+-
+ We create the easy reconcile record
+-
+ !record {model: account.easy.reconcile, id: account_easy_reconcile_0}:
+ name: 'easy reconcile 1'
+ account: account.a_recv
+ reconcile_method:
+ - name: 'easy.reconcile.simple.partner'
+-
+ We call the automatic reconcilation method
+-
+ !python {model: account.easy.reconcile}: |
+ self.run_reconcile(cr, uid, [ref('account_easy_reconcile_0')])
+-
+ I check that customer invoice state is "Paid"
+-
+ !assert {model: account.invoice, id: account_invoice_state2}:
+ - state == 'paid'
\ No newline at end of file
diff --git a/account_easy_reconcile/tests/__init__.py b/account_easy_reconcile/tests/__init__.py
new file mode 100644
index 00000000..c2feb554
--- /dev/null
+++ b/account_easy_reconcile/tests/__init__.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Damien Crier
+# Copyright 2015 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from . import test_onchange_company
+from . import test_reconcile_history
+from . import test_reconcile
+from . import test_scenario_reconcile
diff --git a/account_easy_reconcile/tests/test_onchange_company.py b/account_easy_reconcile/tests/test_onchange_company.py
new file mode 100644
index 00000000..815fd468
--- /dev/null
+++ b/account_easy_reconcile/tests/test_onchange_company.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Damien Crier
+# Copyright 2015 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from openerp.tests import common
+
+
+class testOnChange(common.TransactionCase):
+
+ def setUp(self):
+ super(testOnChange, self).setUp()
+ self.acc_setting_obj = self.registry('account.config.settings')
+ self.company_obj = self.registry('res.company')
+ # analytic defaults account creation
+ self.main_company = self.ref('base.main_company')
+ self.sec_company = self.company_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'name': 'Second company',
+ 'reconciliation_commit_every': 80,
+ }
+ )
+
+ def test_retrieve_analytic_account(self):
+ sec_company_commit = self.company_obj.browse(
+ self.cr,
+ self.uid,
+ self.sec_company).reconciliation_commit_every
+ main_company_commit = self.company_obj.browse(
+ self.cr,
+ self.uid,
+ self.main_company).reconciliation_commit_every
+
+ res1 = self.acc_setting_obj.onchange_company_id(
+ self.cr, self.uid, [], self.sec_company)
+
+ self.assertEqual(sec_company_commit, res1.get(
+ 'value', {}).get('reconciliation_commit_every', False))
+
+ res2 = self.acc_setting_obj.onchange_company_id(
+ self.cr, self.uid, [], self.main_company)
+ self.assertEqual(main_company_commit, res2.get(
+ 'value', {}).get('reconciliation_commit_every', False))
+# self.assertEqual(self.ref('account.analytic_agrolait'), res2.get(
+# 'value', {}).get('reconciliation_commit_every', False))
diff --git a/account_easy_reconcile/tests/test_reconcile.py b/account_easy_reconcile/tests/test_reconcile.py
new file mode 100644
index 00000000..72d2de4b
--- /dev/null
+++ b/account_easy_reconcile/tests/test_reconcile.py
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Damien Crier
+# Copyright 2015 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from openerp.tests import common
+from openerp import fields, exceptions
+
+
+class testReconcile(common.TransactionCase):
+
+ def setUp(self):
+ super(testReconcile, self).setUp()
+ self.rec_history_obj = self.registry('easy.reconcile.history')
+ self.easy_rec_obj = self.registry('account.easy.reconcile')
+ self.easy_rec_method_obj = (
+ self.registry('account.easy.reconcile.method')
+ )
+ self.easy_rec = self.easy_rec_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'name': 'AER2',
+ 'account': self.ref('account.a_salary_expense'),
+ }
+ )
+ self.easy_rec_method = self.easy_rec_method_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'name': 'easy.reconcile.simple.name',
+ 'sequence': '10',
+ 'task_id': self.easy_rec,
+ }
+ )
+ self.easy_rec_no_history = self.easy_rec_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'name': 'AER3',
+ 'account': self.ref('account.a_salary_expense'),
+
+ }
+ )
+ self.rec_history = self.rec_history_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'easy_reconcile_id': self.easy_rec,
+ 'date': fields.Datetime.now(),
+ }
+ )
+
+ def test_last_history(self):
+ easy_rec_last_hist = self.easy_rec_obj.browse(
+ self.cr,
+ self.uid,
+ self.easy_rec
+ ).last_history.id
+ self.assertEqual(self.rec_history, easy_rec_last_hist)
+
+ def test_last_history_empty(self):
+ easy_rec_last_hist = self.easy_rec_obj.browse(
+ self.cr,
+ self.uid,
+ self.easy_rec_no_history
+ ).last_history.id
+ self.assertEqual(False, easy_rec_last_hist)
+
+ def test_last_history_full_no_history(self):
+ with self.assertRaises(exceptions.Warning):
+ self.easy_rec_obj.last_history_reconcile(
+ self.cr, self.uid, [self.easy_rec_no_history])
+
+ def test_last_history_partial_no_history(self):
+ with self.assertRaises(exceptions.Warning):
+ self.easy_rec_obj.last_history_partial(
+ self.cr, self.uid, [self.easy_rec_no_history])
+
+ def test_open_unreconcile(self):
+ res = self.easy_rec_obj.open_unreconcile(
+ self.cr,
+ self.uid,
+ [self.easy_rec]
+ )
+ self.assertEqual(unicode([('id', 'in', [])]), res.get('domain', []))
+
+ def test_open_partial_reconcile(self):
+ res = self.easy_rec_obj.open_partial_reconcile(
+ self.cr,
+ self.uid,
+ [self.easy_rec]
+ )
+ self.assertEqual(unicode([('id', 'in', [])]), res.get('domain', []))
+
+ def test_prepare_run_transient(self):
+ res = self.easy_rec_obj._prepare_run_transient(
+ self.cr,
+ self.uid,
+ self.easy_rec_method_obj.browse(
+ self.cr,
+ self.uid,
+ self.easy_rec_method
+ )
+ )
+ self.assertEqual(self.ref('account.a_salary_expense'),
+ res.get('account_id', 0))
+
+
+class testReconcileNoEasyReconcileAvailable(common.TransactionCase):
+
+ def setUp(self):
+ super(testReconcileNoEasyReconcileAvailable, self).setUp()
+ self.rec_history_obj = self.registry('easy.reconcile.history')
+ self.easy_rec_obj = self.registry('account.easy.reconcile')
+
+# def test_run_scheduler(self):
+# with self.assertRaises(AssertionError):
+# self.easy_rec_obj.run_scheduler(
+# self.cr, self.uid)
diff --git a/account_easy_reconcile/tests/test_reconcile_history.py b/account_easy_reconcile/tests/test_reconcile_history.py
new file mode 100644
index 00000000..3c8a616d
--- /dev/null
+++ b/account_easy_reconcile/tests/test_reconcile_history.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Damien Crier
+# Copyright 2015 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from openerp.tests import common
+from openerp import fields
+
+
+class testReconcileHistory(common.TransactionCase):
+
+ def setUp(self):
+ super(testReconcileHistory, self).setUp()
+ self.rec_history_obj = self.registry('easy.reconcile.history')
+ self.easy_rec_obj = self.registry('account.easy.reconcile')
+ self.easy_rec = self.easy_rec_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'name': 'AER1',
+ 'account': self.ref('account.a_expense'),
+
+ }
+ )
+ self.rec_history = self.rec_history_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'easy_reconcile_id': self.easy_rec,
+ 'date': fields.Datetime.now(),
+ }
+ )
+
+ def test_assert_open_full_partial(self):
+ word = 'test'
+ with self.assertRaises(AssertionError):
+ self.rec_history_obj._open_move_lines(
+ self.cr, self.uid, [self.rec_history], word)
+
+ def test_open_full_empty(self):
+ res = self.rec_history_obj._open_move_lines(
+ self.cr, self.uid, [self.rec_history], 'full')
+ self.assertEqual(unicode([('id', 'in', [])]), res.get(
+ 'domain', []))
+
+ def test_open_full_empty_from_method(self):
+ res = self.rec_history_obj.open_reconcile(
+ self.cr, self.uid, [self.rec_history])
+ self.assertEqual(unicode([('id', 'in', [])]), res.get(
+ 'domain', []))
+
+ def test_open_partial_empty(self):
+ res = self.rec_history_obj._open_move_lines(
+ self.cr, self.uid, [self.rec_history], 'partial')
+ self.assertEqual(unicode([('id', 'in', [])]), res.get(
+ 'domain', []))
+
+ def test_open_partial_empty_from_method(self):
+ res = self.rec_history_obj.open_partial(
+ self.cr, self.uid, [self.rec_history])
+ self.assertEqual(unicode([('id', 'in', [])]), res.get(
+ 'domain', []))
diff --git a/account_easy_reconcile/tests/test_scenario_reconcile.py b/account_easy_reconcile/tests/test_scenario_reconcile.py
new file mode 100644
index 00000000..08da279f
--- /dev/null
+++ b/account_easy_reconcile/tests/test_scenario_reconcile.py
@@ -0,0 +1,298 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Damien Crier
+# Copyright 2015 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from openerp.tests import common
+import time
+
+
+class testScenarioReconcile(common.TransactionCase):
+
+ def setUp(self):
+ super(testScenarioReconcile, self).setUp()
+ self.rec_history_obj = self.registry('easy.reconcile.history')
+ self.easy_rec_obj = self.registry('account.easy.reconcile')
+ self.invoice_obj = self.registry('account.invoice')
+ self.bk_stmt_obj = self.registry('account.bank.statement')
+ self.bk_stmt_line_obj = self.registry('account.bank.statement.line')
+ self.acc_move_line_obj = self.registry('account.move.line')
+ self.easy_rec_method_obj = (
+ self.registry('account.easy.reconcile.method')
+ )
+ self.account_fx_income_id = self.ref("account.income_fx_income")
+ self.account_fx_expense_id = self.ref("account.income_fx_expense")
+ self.acs_model = self.registry('account.config.settings')
+
+ acs_ids = self.acs_model.search(
+ self.cr, self.uid,
+ [('company_id', '=', self.ref("base.main_company"))]
+ )
+
+ values = {'group_multi_currency': True,
+ 'income_currency_exchange_account_id':
+ self.account_fx_income_id,
+ 'expense_currency_exchange_account_id':
+ self.account_fx_expense_id}
+
+ if acs_ids:
+ self.acs_model.write(self.cr, self.uid, acs_ids, values)
+ else:
+ default_vals = self.acs_model.default_get(self.cr, self.uid, [])
+ default_vals.update(values)
+ default_vals['date_stop'] = time.strftime('%Y-12-31')
+ default_vals['date_start'] = time.strftime('%Y-%m-%d')
+ default_vals['period'] = 'month'
+ self.acs_model.create(self.cr, self.uid, default_vals)
+
+ def test_scenario_reconcile(self):
+ # create invoice
+ inv_id = self.invoice_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'type': 'out_invoice',
+ 'account_id': self.ref('account.a_recv'),
+ 'company_id': self.ref('base.main_company'),
+ 'currency_id': self.ref('base.EUR'),
+ 'journal_id': self.ref('account.sales_journal'),
+ 'partner_id': self.ref('base.res_partner_12'),
+ 'invoice_line': [
+ (0, 0, {
+ 'name': '[PCSC234] PC Assemble SC234',
+ 'price_unit': 1000.0,
+ 'quantity': 1.0,
+ 'product_id': self.ref('product.product_product_3'),
+ 'uos_id': self.ref('product.product_uom_unit'),
+ }
+ )
+ ]
+ }
+ )
+ # validate invoice
+ self.invoice_obj.signal_workflow(
+ self.cr,
+ self.uid,
+ [inv_id],
+ 'invoice_open'
+ )
+ invoice_record = self.invoice_obj.browse(self.cr, self.uid, [inv_id])
+ self.assertEqual('open', invoice_record.state)
+
+ # create bank_statement
+ bk_stmt_id = self.bk_stmt_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'balance_end_real': 0.0,
+ 'balance_start': 0.0,
+ 'date': time.strftime('%Y-%m-%d'),
+ 'journal_id': self.ref('account.bank_journal'),
+ 'line_ids': [
+ (0, 0, {
+ 'amount': 1000.0,
+ 'partner_id': self.ref('base.res_partner_12'),
+ 'name': invoice_record.number,
+ 'ref': invoice_record.number,
+ }
+ )
+ ]
+ }
+ )
+
+ # reconcile
+ line_id = None
+ for l in invoice_record.move_id.line_id:
+ if l.account_id.id == self.ref('account.a_recv'):
+ line_id = l
+ break
+
+ statement = self.bk_stmt_obj.browse(self.cr, self.uid, bk_stmt_id)
+ for statement_line in statement.line_ids:
+ self.bk_stmt_line_obj.process_reconciliation(
+ self.cr, self.uid, statement_line.id,
+ [
+ {
+ 'counterpart_move_line_id': line_id.id,
+ 'credit': 1000.0,
+ 'debit': 0.0,
+ 'name': invoice_record.number,
+ }
+ ]
+ )
+ # unreconcile journal item created by previous reconciliation
+ lines_to_unreconcile = self.acc_move_line_obj.search(
+ self.cr,
+ self.uid,
+ [('reconcile_ref', '!=', False),
+ ('statement_id', '=', bk_stmt_id)]
+ )
+ self.acc_move_line_obj._remove_move_reconcile(
+ self.cr,
+ self.uid,
+ lines_to_unreconcile
+ )
+
+ # create the easy reconcile record
+ easy_rec_id = self.easy_rec_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'name': 'easy_reconcile_1',
+ 'account': self.ref('account.a_recv'),
+ 'reconcile_method': [
+ (0, 0, {
+ 'name': 'easy.reconcile.simple.partner',
+ }
+ )
+ ]
+ }
+ )
+ # call the automatic reconcilation method
+ self.easy_rec_obj.run_reconcile(
+ self.cr,
+ self.uid,
+ [easy_rec_id]
+ )
+ self.assertEqual(
+ 'paid',
+ self.invoice_obj.browse(self.cr, self.uid, inv_id).state
+ )
+
+ def test_scenario_reconcile_currency(self):
+ # create currency rate
+ self.registry('res.currency.rate').create(self.cr, self.uid, {
+ 'name': time.strftime('%Y-%m-%d') + ' 00:00:00',
+ 'currency_id': self.ref('base.USD'),
+ 'rate': 1.5,
+ })
+ # create invoice
+ inv_id = self.invoice_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'type': 'out_invoice',
+ 'account_id': self.ref('account.a_recv'),
+ 'company_id': self.ref('base.main_company'),
+ 'currency_id': self.ref('base.USD'),
+ 'journal_id': self.ref('account.bank_journal_usd'),
+ 'partner_id': self.ref('base.res_partner_12'),
+ 'invoice_line': [
+ (0, 0, {
+ 'name': '[PCSC234] PC Assemble SC234',
+ 'price_unit': 1000.0,
+ 'quantity': 1.0,
+ 'product_id': self.ref('product.product_product_3'),
+ 'uos_id': self.ref('product.product_uom_unit'),
+ }
+ )
+ ]
+ }
+ )
+ # validate invoice
+ self.invoice_obj.signal_workflow(
+ self.cr,
+ self.uid,
+ [inv_id],
+ 'invoice_open'
+ )
+ invoice_record = self.invoice_obj.browse(self.cr, self.uid, [inv_id])
+ self.assertEqual('open', invoice_record.state)
+
+ # create bank_statement
+ bk_stmt_id = self.bk_stmt_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'balance_end_real': 0.0,
+ 'balance_start': 0.0,
+ 'date': time.strftime('%Y-%m-%d'),
+ 'journal_id': self.ref('account.bank_journal_usd'),
+ 'line_ids': [
+ (0, 0, {
+ 'amount': 1000.0,
+ 'amount_currency': 1500.0,
+ 'currency_id': self.ref('base.USD'),
+ 'partner_id': self.ref('base.res_partner_12'),
+ 'name': invoice_record.number,
+ 'ref': invoice_record.number,
+ }
+ )
+ ]
+ }
+ )
+
+ # reconcile
+ line_id = None
+ for l in invoice_record.move_id.line_id:
+ if l.account_id.id == self.ref('account.a_recv'):
+ line_id = l
+ break
+
+ statement = self.bk_stmt_obj.browse(self.cr, self.uid, bk_stmt_id)
+ for statement_line in statement.line_ids:
+ self.bk_stmt_line_obj.process_reconciliation(
+ self.cr, self.uid, statement_line.id,
+ [
+ {
+ 'counterpart_move_line_id': line_id.id,
+ 'credit': 1000.0,
+ 'debit': 0.0,
+ 'name': invoice_record.number,
+ }
+ ]
+ )
+ # unreconcile journal item created by previous reconciliation
+ lines_to_unreconcile = self.acc_move_line_obj.search(
+ self.cr,
+ self.uid,
+ [('reconcile_ref', '!=', False),
+ ('statement_id', '=', bk_stmt_id)]
+ )
+ self.acc_move_line_obj._remove_move_reconcile(
+ self.cr,
+ self.uid,
+ lines_to_unreconcile
+ )
+
+ # create the easy reconcile record
+ easy_rec_id = self.easy_rec_obj.create(
+ self.cr,
+ self.uid,
+ {
+ 'name': 'easy_reconcile_1',
+ 'account': self.ref('account.a_recv'),
+ 'reconcile_method': [
+ (0, 0, {
+ 'name': 'easy.reconcile.simple.partner',
+ }
+ )
+ ]
+ }
+ )
+ # call the automatic reconcilation method
+ self.easy_rec_obj.run_reconcile(
+ self.cr,
+ self.uid,
+ [easy_rec_id]
+ )
+ self.assertEqual(
+ 'paid',
+ self.invoice_obj.browse(self.cr, self.uid, inv_id).state
+ )