diff --git a/account_advanced_reconcile/__init__.py b/account_advanced_reconcile/__init__.py new file mode 100644 index 00000000..e1a57902 --- /dev/null +++ b/account_advanced_reconcile/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Contributor: Leonardo Pistone +# Copyright 2012-2014 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 easy_reconcile +from . import base_advanced_reconciliation +from . import advanced_reconciliation diff --git a/account_advanced_reconcile/__openerp__.py b/account_advanced_reconcile/__openerp__.py new file mode 100644 index 00000000..ffe335dc --- /dev/null +++ b/account_advanced_reconcile/__openerp__.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Contributor: Leonardo Pistone +# Copyright 2012-2014 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 . +# +############################################################################## + +{'name': "Advanced Reconcile", + 'version': '1.0', + 'author': "Camptocamp,Odoo Community Association (OCA)", + 'maintainer': 'Camptocamp', + 'category': 'Finance', + 'complexity': 'normal', + 'depends': ['account_easy_reconcile', + ], + 'description': """ +Advanced reconciliation methods for the module account_easy_reconcile. + +In addition to the features implemented in account_easy_reconcile, which are: + - 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 reconcilation runs with an history + +It implements a basis to created advanced reconciliation methods in a few lines +of code. + +Typically, such a method can be: + - Reconcile Journal items if the partner and the ref are equal + - Reconcile Journal items if the partner is equal and the ref + is the same than ref or name + - Reconcile Journal items if the partner is equal and the ref + match with a pattern + +And they allows: + - Reconciliations with multiple credit / multiple debit lines + - Partial reconciliations + - Write-off amount as well + +A method is already implemented in this module, it matches on items: + - Partner + - Ref on credit move lines should be case insensitive equals to the ref or + the name of the debit move line + +The base class to find the reconciliations is built to be as efficient as +possible. + +So basically, if you have an invoice with 3 payments (one per month), the first +month, it will partial reconcile the debit move line with the first payment, +the second month, it will partial reconcile the debit move line with 2 first +payments, the third month, it will make the full reconciliation. + +This module is perfectly adapted for E-Commerce business where a big volume of +move lines and so, reconciliations, are involved and payments often come from +many offices. + + """, + 'website': 'http://www.camptocamp.com', + 'data': ['easy_reconcile_view.xml', + ], + 'test': [], + 'images': [], + 'installable': False, + 'auto_install': False, + 'license': 'AGPL-3', + 'application': True, + } diff --git a/account_advanced_reconcile/advanced_reconciliation.py b/account_advanced_reconcile/advanced_reconciliation.py new file mode 100644 index 00000000..5ac292c1 --- /dev/null +++ b/account_advanced_reconcile/advanced_reconciliation.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright 2012 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.osv import orm + + +class easy_reconcile_advanced_ref(orm.TransientModel): + + _name = 'easy.reconcile.advanced.ref' + _inherit = 'easy.reconcile.advanced' + + def _skip_line(self, cr, uid, rec, move_line, context=None): + """ + When True is returned on some conditions, the credit move line + will be skipped for reconciliation. Can be inherited to + skip on some conditions. ie: ref or partner_id is empty. + """ + return not (move_line.get('ref') and move_line.get('partner_id')) + + def _matchers(self, cr, uid, rec, move_line, context=None): + """ + Return the values used as matchers to find the opposite lines + + All the matcher keys in the dict must have their equivalent in + the `_opposite_matchers`. + + The values of each matcher key will be searched in the + one returned by the `_opposite_matchers` + + Must be inherited to implement the matchers for one method + + For instance, it can return: + return ('ref', move_line['rec']) + + or + return (('partner_id', move_line['partner_id']), + ('ref', "prefix_%s" % move_line['rec'])) + + All the matchers have to be found in the opposite lines + to consider them as "opposite" + + The matchers will be evaluated in the same order as declared + vs the the opposite matchers, so you can gain performance by + declaring first the partners with the less computation. + + All matchers should match with their opposite to be considered + as "matching". + So with the previous example, partner_id and ref have to be + equals on the opposite line matchers. + + :return: tuple of tuples (key, value) where the keys are + the matchers keys + (must be the same than `_opposite_matchers` returns, + and their values to match in the opposite lines. + A matching key can have multiples values. + """ + return (('partner_id', move_line['partner_id']), + ('ref', move_line['ref'].lower().strip())) + + def _opposite_matchers(self, cr, uid, rec, move_line, context=None): + """ + Return the values of the opposite line used as matchers + so the line is matched + + Must be inherited to implement the matchers for one method + It can be inherited to apply some formatting of fields + (strip(), lower() and so on) + + This method is the counterpart of the `_matchers()` method. + + Each matcher has to yield its value respecting the order + of the `_matchers()`. + + When a matcher does not correspond, the next matchers won't + be evaluated so the ones which need the less computation + have to be executed first. + + If the `_matchers()` returns: + (('partner_id', move_line['partner_id']), + ('ref', move_line['ref'])) + + Here, you should yield : + yield ('partner_id', move_line['partner_id']) + yield ('ref', move_line['ref']) + + Note that a matcher can contain multiple values, as instance, + if for a move line, you want to search from its `ref` in the + `ref` or `name` fields of the opposite move lines, you have to + yield ('partner_id', move_line['partner_id']) + yield ('ref', (move_line['ref'], move_line['name']) + + An OR is used between the values for the same key. + An AND is used between the differents keys. + + :param dict move_line: values of the move_line + :yield: matchers as tuple ('matcher key', value(s)) + """ + yield ('partner_id', move_line['partner_id']) + yield ('ref', ((move_line['ref'] or '').lower().strip(), + move_line['name'].lower().strip())) diff --git a/account_advanced_reconcile/base_advanced_reconciliation.py b/account_advanced_reconcile/base_advanced_reconciliation.py new file mode 100644 index 00000000..a9fe439c --- /dev/null +++ b/account_advanced_reconcile/base_advanced_reconciliation.py @@ -0,0 +1,287 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Contributor: Leonardo Pistone +# Copyright 2012-2014 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 . +# +############################################################################## +import logging + +from itertools import product +from openerp.osv import orm +from openerp.tools.translate import _ + +_logger = logging.getLogger(__name__) + + +class easy_reconcile_advanced(orm.AbstractModel): + _name = 'easy.reconcile.advanced' + _inherit = 'easy.reconcile.base' + + def _query_debit(self, cr, uid, rec, context=None): + """Select all move (debit>0) as candidate. """ + select = self._select(rec) + sql_from = self._from(rec) + where, params = self._where(rec) + where += " AND account_move_line.debit > 0 " + where2, params2 = self._get_filter(cr, uid, rec, context=context) + query = ' '.join((select, sql_from, where, where2)) + cr.execute(query, params + params2) + return cr.dictfetchall() + + def _query_credit(self, cr, uid, rec, context=None): + """Select all move (credit>0) as candidate. """ + select = self._select(rec) + sql_from = self._from(rec) + where, params = self._where(rec) + where += " AND account_move_line.credit > 0 " + where2, params2 = self._get_filter(cr, uid, rec, context=context) + query = ' '.join((select, sql_from, where, where2)) + cr.execute(query, params + params2) + return cr.dictfetchall() + + def _matchers(self, cr, uid, rec, move_line, context=None): + """ + Return the values used as matchers to find the opposite lines + + All the matcher keys in the dict must have their equivalent in + the `_opposite_matchers`. + + The values of each matcher key will be searched in the + one returned by the `_opposite_matchers` + + Must be inherited to implement the matchers for one method + + As instance, it can return: + return ('ref', move_line['rec']) + + or + return (('partner_id', move_line['partner_id']), + ('ref', "prefix_%s" % move_line['rec'])) + + All the matchers have to be found in the opposite lines + to consider them as "opposite" + + The matchers will be evaluated in the same order as declared + vs the the opposite matchers, so you can gain performance by + declaring first the partners with the less computation. + + All matchers should match with their opposite to be considered + as "matching". + So with the previous example, partner_id and ref have to be + equals on the opposite line matchers. + + :return: tuple of tuples (key, value) where the keys are + the matchers keys + (must be the same than `_opposite_matchers` returns, + and their values to match in the opposite lines. + A matching key can have multiples values. + """ + raise NotImplementedError + + def _opposite_matchers(self, cr, uid, rec, move_line, context=None): + """ + Return the values of the opposite line used as matchers + so the line is matched + + Must be inherited to implement the matchers for one method + It can be inherited to apply some formatting of fields + (strip(), lower() and so on) + + This method is the counterpart of the `_matchers()` method. + + Each matcher has to yield its value respecting the order + of the `_matchers()`. + + When a matcher does not correspond, the next matchers won't + be evaluated so the ones which need the less computation + have to be executed first. + + If the `_matchers()` returns: + (('partner_id', move_line['partner_id']), + ('ref', move_line['ref'])) + + Here, you should yield : + yield ('partner_id', move_line['partner_id']) + yield ('ref', move_line['ref']) + + Note that a matcher can contain multiple values, as instance, + if for a move line, you want to search from its `ref` in the + `ref` or `name` fields of the opposite move lines, you have to + yield ('partner_id', move_line['partner_id']) + yield ('ref', (move_line['ref'], move_line['name']) + + An OR is used between the values for the same key. + An AND is used between the differents keys. + + :param dict move_line: values of the move_line + :yield: matchers as tuple ('matcher key', value(s)) + """ + raise NotImplementedError + + @staticmethod + def _compare_values(key, value, opposite_value): + """Can be inherited to modify the equality condition + specifically according to the matcher key (maybe using + a like operator instead of equality on 'ref' as instance) + """ + # consider that empty vals are not valid matchers + # it can still be inherited for some special cases + # where it would be allowed + if not (value and opposite_value): + return False + + if value == opposite_value: + return True + return False + + @staticmethod + def _compare_matcher_values(key, values, opposite_values): + """ Compare every values from a matcher vs an opposite matcher + and return True if it matches + """ + for value, ovalue in product(values, opposite_values): + # we do not need to compare all values, if one matches + # we are done + if easy_reconcile_advanced._compare_values(key, value, ovalue): + return True + return False + + @staticmethod + def _compare_matchers(matcher, opposite_matcher): + """ + Prepare and check the matchers to compare + """ + mkey, mvalue = matcher + omkey, omvalue = opposite_matcher + assert mkey == omkey, \ + (_("A matcher %s is compared with a matcher %s, the _matchers and " + "_opposite_matchers are probably wrong") % (mkey, omkey)) + if not isinstance(mvalue, (list, tuple)): + mvalue = mvalue, + if not isinstance(omvalue, (list, tuple)): + omvalue = omvalue, + return easy_reconcile_advanced._compare_matcher_values(mkey, mvalue, + omvalue) + + def _compare_opposite(self, cr, uid, rec, move_line, opposite_move_line, + matchers, context=None): + """ Iterate over the matchers of the move lines vs opposite move lines + and if they all match, return True. + + If all the matchers match for a move line and an opposite move line, + they are candidate for a reconciliation. + """ + opp_matchers = self._opposite_matchers(cr, uid, rec, + opposite_move_line, + context=context) + for matcher in matchers: + try: + opp_matcher = opp_matchers.next() + except StopIteration: + # if you fall here, you probably missed to put a `yield` + # in `_opposite_matchers()` + raise ValueError("Missing _opposite_matcher: %s" % matcher[0]) + + if not self._compare_matchers(matcher, opp_matcher): + # if any of the matcher fails, the opposite line + # is not a valid counterpart + # directly returns so the next yield of _opposite_matchers + # are not evaluated + return False + + return True + + def _search_opposites(self, cr, uid, rec, move_line, opposite_move_lines, + context=None): + """Search the opposite move lines for a move line + + :param dict move_line: the move line for which we search opposites + :param list opposite_move_lines: list of dict of move lines values, + the move lines we want to search for + :return: list of matching lines + """ + matchers = self._matchers(cr, uid, rec, move_line, context=context) + return [op for op in opposite_move_lines if + self._compare_opposite( + cr, uid, rec, move_line, op, matchers, context=context)] + + def _action_rec(self, cr, uid, rec, context=None): + credit_lines = self._query_credit(cr, uid, rec, context=context) + debit_lines = self._query_debit(cr, uid, rec, context=context) + result = self._rec_auto_lines_advanced( + cr, uid, rec, credit_lines, debit_lines, context=context) + return result + + def _skip_line(self, cr, uid, rec, move_line, context=None): + """ + When True is returned on some conditions, the credit move line + will be skipped for reconciliation. Can be inherited to + skip on some conditions. ie: ref or partner_id is empty. + """ + return False + + def _rec_auto_lines_advanced(self, cr, uid, rec, credit_lines, debit_lines, + context=None): + """ Advanced reconciliation main loop """ + reconciled_ids = [] + partial_reconciled_ids = [] + reconcile_groups = [] + _logger.info("%d credit lines to reconcile", len(credit_lines)) + for idx, credit_line in enumerate(credit_lines, start=1): + if idx % 50 == 0: + _logger.info("... %d/%d credit lines inspected ...", idx, + len(credit_lines)) + if self._skip_line(cr, uid, rec, credit_line, context=context): + continue + opposite_lines = self._search_opposites( + cr, uid, rec, credit_line, debit_lines, context=context) + if not opposite_lines: + continue + opposite_ids = [l['id'] for l in opposite_lines] + line_ids = opposite_ids + [credit_line['id']] + for group in reconcile_groups: + if any([lid in group for lid in opposite_ids]): + _logger.debug("New lines %s matched with an existing " + "group %s", line_ids, group) + group.update(line_ids) + break + else: + _logger.debug("New group of lines matched %s", line_ids) + reconcile_groups.append(set(line_ids)) + lines_by_id = dict([(l['id'], l) for l in credit_lines + debit_lines]) + _logger.info("Found %d groups to reconcile", len(reconcile_groups)) + for group_count, reconcile_group_ids in enumerate(reconcile_groups, + start=1): + _logger.debug("Reconciling group %d/%d with ids %s", + group_count, len(reconcile_groups), + reconcile_group_ids) + group_lines = [lines_by_id[lid] for lid in reconcile_group_ids] + reconciled, full = self._reconcile_lines( + cr, uid, rec, group_lines, allow_partial=True, context=context) + if reconciled and full: + reconciled_ids += reconcile_group_ids + elif reconciled: + partial_reconciled_ids += reconcile_group_ids + + if (context['commit_every'] and + group_count % context['commit_every'] == 0): + cr.commit() + _logger.info("Commit the reconciliations after %d groups", + group_count) + _logger.info("Reconciliation is over") + return reconciled_ids, partial_reconciled_ids diff --git a/account_advanced_reconcile/easy_reconcile.py b/account_advanced_reconcile/easy_reconcile.py new file mode 100644 index 00000000..5506917b --- /dev/null +++ b/account_advanced_reconcile/easy_reconcile.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright 2012 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.osv import orm + + +class account_easy_reconcile_method(orm.Model): + + _inherit = 'account.easy.reconcile.method' + + def _get_all_rec_method(self, cr, uid, context=None): + methods = super(account_easy_reconcile_method, self).\ + _get_all_rec_method(cr, uid, context=context) + methods += [ + ('easy.reconcile.advanced.ref', + 'Advanced. Partner and Ref.'), + ] + return methods diff --git a/account_advanced_reconcile/easy_reconcile_view.xml b/account_advanced_reconcile/easy_reconcile_view.xml new file mode 100644 index 00000000..7d35927d --- /dev/null +++ b/account_advanced_reconcile/easy_reconcile_view.xml @@ -0,0 +1,19 @@ + + + + + account.easy.reconcile.form + account.easy.reconcile + + + + + + + + + + + diff --git a/account_advanced_reconcile/i18n/account_advanced_reconcile.pot b/account_advanced_reconcile/i18n/account_advanced_reconcile.pot new file mode 100644 index 00000000..98382751 --- /dev/null +++ b/account_advanced_reconcile/i18n/account_advanced_reconcile.pot @@ -0,0 +1,90 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * account_advanced_reconcile +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-01-21 11:54+0000\n" +"PO-Revision-Date: 2014-01-21 11:54+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,partner_ids:0 +#: field:easy.reconcile.advanced.ref,partner_ids:0 +msgid "Restrict on partners" +msgstr "" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,account_id:0 +#: field:easy.reconcile.advanced.ref,account_id:0 +msgid "Account" +msgstr "" + +#. module: account_advanced_reconcile +#: model:ir.model,name:account_advanced_reconcile.model_account_easy_reconcile_method +msgid "reconcile method for account_easy_reconcile" +msgstr "" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,journal_id:0 +#: field:easy.reconcile.advanced.ref,journal_id:0 +msgid "Journal" +msgstr "" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,account_profit_id:0 +#: field:easy.reconcile.advanced.ref,account_profit_id:0 +msgid "Account Profit" +msgstr "" + +#. module: account_advanced_reconcile +#: view:account.easy.reconcile:0 +msgid "Match multiple debit vs multiple credit entries. Allow partial reconciliation. The lines should have the partner, the credit entry ref. is matched vs the debit entry ref. or name." +msgstr "" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,filter:0 +#: field:easy.reconcile.advanced.ref,filter:0 +msgid "Filter" +msgstr "" + +#. module: account_advanced_reconcile +#: view:account.easy.reconcile:0 +msgid "Advanced. Partner and Ref" +msgstr "" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,date_base_on:0 +#: field:easy.reconcile.advanced.ref,date_base_on:0 +msgid "Date of reconciliation" +msgstr "" + +#. module: account_advanced_reconcile +#: model:ir.model,name:account_advanced_reconcile.model_easy_reconcile_advanced +msgid "easy.reconcile.advanced" +msgstr "" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,account_lost_id:0 +#: field:easy.reconcile.advanced.ref,account_lost_id:0 +msgid "Account Lost" +msgstr "" + +#. module: account_advanced_reconcile +#: model:ir.model,name:account_advanced_reconcile.model_easy_reconcile_advanced_ref +msgid "easy.reconcile.advanced.ref" +msgstr "" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,write_off:0 +#: field:easy.reconcile.advanced.ref,write_off:0 +msgid "Write off allowed" +msgstr "" + diff --git a/account_advanced_reconcile/i18n/es.po b/account_advanced_reconcile/i18n/es.po new file mode 100644 index 00000000..cc47462f --- /dev/null +++ b/account_advanced_reconcile/i18n/es.po @@ -0,0 +1,98 @@ +# Spanish translation for banking-addons +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the banking-addons package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: banking-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2014-01-21 11:54+0000\n" +"PO-Revision-Date: 2014-06-05 22:30+0000\n" +"Last-Translator: Pedro Manuel Baeza \n" +"Language-Team: Spanish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2014-06-06 06:36+0000\n" +"X-Generator: Launchpad (build 17031)\n" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,partner_ids:0 +#: field:easy.reconcile.advanced.ref,partner_ids:0 +msgid "Restrict on partners" +msgstr "Restringir a las empresas" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,account_id:0 +#: field:easy.reconcile.advanced.ref,account_id:0 +msgid "Account" +msgstr "Cuenta" + +#. module: account_advanced_reconcile +#: model:ir.model,name:account_advanced_reconcile.model_account_easy_reconcile_method +msgid "reconcile method for account_easy_reconcile" +msgstr "método de conciliación para account_easy_reconcile" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,journal_id:0 +#: field:easy.reconcile.advanced.ref,journal_id:0 +msgid "Journal" +msgstr "Diario" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,account_profit_id:0 +#: field:easy.reconcile.advanced.ref,account_profit_id:0 +msgid "Account Profit" +msgstr "Cuenta de ganancias" + +#. module: account_advanced_reconcile +#: view:account.easy.reconcile:0 +msgid "" +"Match multiple debit vs multiple credit entries. Allow partial " +"reconciliation. The lines should have the partner, the credit entry ref. is " +"matched vs the debit entry ref. or name." +msgstr "" +"Casa múltiples líneas del debe con múltiples líneas del haber. Permite " +"conciliación parcial. Las líneas deben tener la empresa, la referencia de la " +"línea del haber se casa contra la referencia de la línea del debe o el " +"nombre." + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,filter:0 +#: field:easy.reconcile.advanced.ref,filter:0 +msgid "Filter" +msgstr "Filtro" + +#. module: account_advanced_reconcile +#: view:account.easy.reconcile:0 +msgid "Advanced. Partner and Ref" +msgstr "Avanzado. Empresa y referencia" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,date_base_on:0 +#: field:easy.reconcile.advanced.ref,date_base_on:0 +msgid "Date of reconciliation" +msgstr "Fecha de conciliación" + +#. module: account_advanced_reconcile +#: model:ir.model,name:account_advanced_reconcile.model_easy_reconcile_advanced +msgid "easy.reconcile.advanced" +msgstr "easy.reconcile.advanced" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,account_lost_id:0 +#: field:easy.reconcile.advanced.ref,account_lost_id:0 +msgid "Account Lost" +msgstr "Cuenta de pérdidas" + +#. module: account_advanced_reconcile +#: model:ir.model,name:account_advanced_reconcile.model_easy_reconcile_advanced_ref +msgid "easy.reconcile.advanced.ref" +msgstr "easy.reconcile.advanced.ref" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,write_off:0 +#: field:easy.reconcile.advanced.ref,write_off:0 +msgid "Write off allowed" +msgstr "Desajuste permitido" diff --git a/account_advanced_reconcile/i18n/fr.po b/account_advanced_reconcile/i18n/fr.po new file mode 100644 index 00000000..0c3e9eb9 --- /dev/null +++ b/account_advanced_reconcile/i18n/fr.po @@ -0,0 +1,98 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * account_advanced_reconcile +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 6.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-01-21 11:54+0000\n" +"PO-Revision-Date: 2014-03-21 15:24+0000\n" +"Last-Translator: Guewen Baconnier @ Camptocamp \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2014-05-22 06:49+0000\n" +"X-Generator: Launchpad (build 17017)\n" +"Language: \n" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,partner_ids:0 +#: field:easy.reconcile.advanced.ref,partner_ids:0 +msgid "Restrict on partners" +msgstr "Restriction sur les partenaires" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,account_id:0 +#: field:easy.reconcile.advanced.ref,account_id:0 +msgid "Account" +msgstr "Compte" + +#. module: account_advanced_reconcile +#: model:ir.model,name:account_advanced_reconcile.model_account_easy_reconcile_method +msgid "reconcile method for account_easy_reconcile" +msgstr "Méthode de lettrage pour le module account_easy_reconcile" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,journal_id:0 +#: field:easy.reconcile.advanced.ref,journal_id:0 +msgid "Journal" +msgstr "Journal" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,account_profit_id:0 +#: field:easy.reconcile.advanced.ref,account_profit_id:0 +msgid "Account Profit" +msgstr "Compte de produit" + +#. module: account_advanced_reconcile +#: view:account.easy.reconcile:0 +msgid "" +"Match multiple debit vs multiple credit entries. Allow partial " +"reconciliation. The lines should have the partner, the credit entry ref. is " +"matched vs the debit entry ref. or name." +msgstr "" +"Le Lettrage peut s'effectuer sur plusieurs écritures de débit et crédit. Le " +"Lettrage partiel est autorisé. Les écritures doivent avoir le même " +"partenaire et la référence sur les écritures de crédit doit se retrouver " +"dans la référence ou la description sur les écritures de débit." + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,filter:0 +#: field:easy.reconcile.advanced.ref,filter:0 +msgid "Filter" +msgstr "Filtre" + +#. module: account_advanced_reconcile +#: view:account.easy.reconcile:0 +msgid "Advanced. Partner and Ref" +msgstr "Avancé. Partenaire et Réf." + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,date_base_on:0 +#: field:easy.reconcile.advanced.ref,date_base_on:0 +msgid "Date of reconciliation" +msgstr "Date de lettrage" + +#. module: account_advanced_reconcile +#: model:ir.model,name:account_advanced_reconcile.model_easy_reconcile_advanced +msgid "easy.reconcile.advanced" +msgstr "easy.reconcile.advanced" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,account_lost_id:0 +#: field:easy.reconcile.advanced.ref,account_lost_id:0 +msgid "Account Lost" +msgstr "Compte de charge" + +#. module: account_advanced_reconcile +#: model:ir.model,name:account_advanced_reconcile.model_easy_reconcile_advanced_ref +msgid "easy.reconcile.advanced.ref" +msgstr "easy.reconcile.advanced.ref" + +#. module: account_advanced_reconcile +#: field:easy.reconcile.advanced,write_off:0 +#: field:easy.reconcile.advanced.ref,write_off:0 +msgid "Write off allowed" +msgstr "Écart autorisé" diff --git a/account_advanced_reconcile/res_config.py b/account_advanced_reconcile/res_config.py new file mode 100644 index 00000000..cb827ab3 --- /dev/null +++ b/account_advanced_reconcile/res_config.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Leonardo Pistone +# Copyright 2014 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.osv import orm, fields + + +class AccountConfigSettings(orm.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."""), + } + + def onchange_company_id(self, cr, uid, ids, company_id, context=None): + company_obj = self.pool['res.company'] + + result = super(AccountConfigSettings, self).onchange_company_id( + cr, uid, ids, company_id, context=None) + + if company_id: + company = company_obj.browse(cr, uid, company_id, context=context) + result['value']['reconciliation_commit_every'] = ( + company.reconciliation_commit_every + ) + return result + + +class Company(orm.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."""), + } diff --git a/account_advanced_reconcile/res_config_view.xml b/account_advanced_reconcile/res_config_view.xml new file mode 100644 index 00000000..8badc32e --- /dev/null +++ b/account_advanced_reconcile/res_config_view.xml @@ -0,0 +1,24 @@ + + + + + account settings + account.config.settings + + + + + + + + + + +