mirror of
https://github.com/OCA/account-reconcile.git
synced 2025-01-20 12:27:39 +02:00
Merge branch '7.0' into 8.0
Conflicts: .travis.yml __unported__/account_advanced_reconcile/res_config.py __unported__/account_advanced_reconcile/res_config_view.xml __unported__/account_statement_base_completion/__openerp__.py __unported__/account_statement_base_completion/i18n/fr.po account_advanced_reconcile/res_config.py account_advanced_reconcile/res_config_view.xml account_easy_reconcile/res_config.py account_easy_reconcile/res_config_view.xml account_invoice_reference/__openerp__.py account_invoice_reference/account_move.py statement_voucher_killer/__openerp__.py statement_voucher_killer/voucher.py
This commit is contained in:
@@ -3,6 +3,7 @@ include =
|
||||
*/bank-statement-reconcile/*
|
||||
|
||||
omit =
|
||||
*/test/*
|
||||
*/tests/*
|
||||
*__init__.py
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import easy_reconcile
|
||||
import base_advanced_reconciliation
|
||||
import advanced_reconciliation
|
||||
import res_config # noqa
|
||||
from . import easy_reconcile
|
||||
from . import base_advanced_reconciliation
|
||||
from . import advanced_reconciliation
|
||||
|
||||
@@ -64,8 +64,8 @@ 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
|
||||
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
|
||||
@@ -75,7 +75,7 @@ many offices.
|
||||
""",
|
||||
'website': 'http://www.camptocamp.com',
|
||||
'data': ['easy_reconcile_view.xml',
|
||||
'res_config_view.xml'],
|
||||
],
|
||||
'test': [],
|
||||
'images': [],
|
||||
'installable': False,
|
||||
|
||||
@@ -23,10 +23,8 @@ import logging
|
||||
|
||||
from itertools import product
|
||||
from openerp.osv import orm
|
||||
from openerp import pooler
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -188,7 +186,8 @@ class easy_reconcile_advanced(orm.AbstractModel):
|
||||
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,
|
||||
opp_matchers = self._opposite_matchers(cr, uid, rec,
|
||||
opposite_move_line,
|
||||
context=context)
|
||||
for matcher in matchers:
|
||||
try:
|
||||
@@ -222,29 +221,10 @@ class easy_reconcile_advanced(orm.AbstractModel):
|
||||
cr, uid, rec, move_line, op, matchers, context=context)]
|
||||
|
||||
def _action_rec(self, cr, uid, rec, context=None):
|
||||
# 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.
|
||||
if context is None:
|
||||
context = {}
|
||||
ctx = context.copy()
|
||||
ctx['commit_every'] = (
|
||||
rec.journal_id.company_id.reconciliation_commit_every
|
||||
)
|
||||
if ctx['commit_every']:
|
||||
new_cr = pooler.get_db(cr.dbname).cursor()
|
||||
else:
|
||||
new_cr = cr
|
||||
try:
|
||||
credit_lines = self._query_credit(new_cr, uid, rec, context=ctx)
|
||||
debit_lines = self._query_debit(new_cr, uid, rec, context=ctx)
|
||||
result = self._rec_auto_lines_advanced(
|
||||
new_cr, uid, rec, credit_lines, debit_lines, context=ctx)
|
||||
finally:
|
||||
if ctx['commit_every']:
|
||||
new_cr.commit()
|
||||
new_cr.close()
|
||||
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):
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Matthieu Dietrich
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from . import easy_reconcile
|
||||
from . import advanced_reconciliation
|
||||
@@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Matthieu Dietrich
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{'name': 'Advanced Reconcile Bank Statement',
|
||||
'description': """
|
||||
Advanced reconciliation method for the module account_advanced_reconcile
|
||||
========================================================================
|
||||
Reconcile rules with bank statement name.
|
||||
|
||||
This will reconcile multiple credit move lines (bank statements) with
|
||||
all the lines from a specific bank statement, debit or credit (to also
|
||||
reconcile the commission with credit card imports).
|
||||
|
||||
""",
|
||||
'version': '1.0.0',
|
||||
'author': 'Camptocamp',
|
||||
'category': 'Finance',
|
||||
'website': 'http://www.camptocamp.com',
|
||||
'depends': ['account_advanced_reconcile'],
|
||||
'data': ['easy_reconcile_view.xml'],
|
||||
'demo': [],
|
||||
'test': [],
|
||||
'auto_install': False,
|
||||
'installable': True,
|
||||
'images': []
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Matthieu Dietrich. Copyright 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import orm
|
||||
|
||||
|
||||
class easy_reconcile_advanced_bank_statement(orm.TransientModel):
|
||||
|
||||
_name = 'easy.reconcile.advanced.bank_statement'
|
||||
_inherit = 'easy.reconcile.advanced'
|
||||
|
||||
def _base_columns(self, rec):
|
||||
""" Mandatory columns for move lines queries
|
||||
An extra column aliased as ``key`` should be defined
|
||||
in each query."""
|
||||
aml_cols = super(easy_reconcile_advanced_bank_statement, self).\
|
||||
_base_columns(rec)
|
||||
aml_cols += ['account_move_line.statement_id',
|
||||
'account_bank_statement.name as statement_name',
|
||||
]
|
||||
return aml_cols
|
||||
|
||||
def _from(self, rec, *args, **kwargs):
|
||||
result = super(easy_reconcile_advanced_bank_statement, self).\
|
||||
_from(rec, *args, **kwargs)
|
||||
result = result + (
|
||||
" INNER JOIN account_bank_statement "
|
||||
"ON account_bank_statement.id = account_move_line.statement_id "
|
||||
)
|
||||
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.
|
||||
"""
|
||||
result = super(easy_reconcile_advanced_bank_statement, self).\
|
||||
_skip_line(cr, uid, rec, move_line, context=context)
|
||||
if result:
|
||||
return result
|
||||
return not (move_line.get('ref') and
|
||||
move_line.get('partner_id'))
|
||||
|
||||
def _matchers(self, cr, uid, rec, move_line, context=None):
|
||||
return (('partner_id', move_line['partner_id']),
|
||||
('ref', move_line['ref'].lower().strip()))
|
||||
|
||||
def _opposite_matchers(self, cr, uid, rec, move_line, context=None):
|
||||
yield ('partner_id', move_line['partner_id'])
|
||||
yield ('ref',
|
||||
(move_line['statement_name'] or '').lower().strip())
|
||||
|
||||
# Re-defined for this particular rule; since the commission line is a
|
||||
# credit line inside of the target statement, it should also be considered
|
||||
# as an opposite to be reconciled.
|
||||
# And also, given some are refunds, debit lines can be "credit".
|
||||
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)
|
||||
return self._rec_auto_lines_advanced(cr, uid, rec,
|
||||
credit_lines + debit_lines,
|
||||
credit_lines + debit_lines,
|
||||
context=context)
|
||||
@@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Matthieu Dietrich
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
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.bank_statement',
|
||||
'Advanced. Partner and Bank Statement'),
|
||||
]
|
||||
return methods
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="0">
|
||||
<record id="view_easy_reconcile_form" model="ir.ui.view">
|
||||
<field name="name">account.easy.reconcile.form</field>
|
||||
<field name="model">account.easy.reconcile</field>
|
||||
<field name="inherit_id" ref="account_easy_reconcile.account_easy_reconcile_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<page name="information" position="inside">
|
||||
<group colspan="2" col="2">
|
||||
<separator colspan="4" string="Advanced. Partner and Bank Statement"/>
|
||||
<label string="Match multiple debit vs multiple credit entries. Allow partial reconciliation.
|
||||
The lines should have the partner, the credit entry reference is matched vs the debit entry bank statement name." colspan="4"/>
|
||||
</group>
|
||||
</page>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,107 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_advanced_reconcile_bank_statement
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-05-27 08:36+0000\n"
|
||||
"PO-Revision-Date: 2014-05-27 08:36+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_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,filter:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_filter
|
||||
msgid "Filter"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,account_id:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_account_id
|
||||
msgid "Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,partner_ids:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_partner_ids
|
||||
msgid "Restrict on partners"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: code:_description:0
|
||||
#: model:ir.model,name:account_advanced_reconcile_bank_statement.model_easy_reconcile_advanced_bank_statement
|
||||
#, python-format
|
||||
msgid "easy.reconcile.advanced.bank_statement"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: 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 reference is matched vs the debit entry bank statement name."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,journal_id:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_journal_id
|
||||
msgid "Journal"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,account_profit_id:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_account_profit_id
|
||||
msgid "Account Profit"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,analytic_account_id:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_analytic_account_id
|
||||
msgid "Analytic Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: code:_description:0
|
||||
#: model:ir.model,name:account_advanced_reconcile_bank_statement.model_account_easy_reconcile_method
|
||||
#, python-format
|
||||
msgid "reconcile method for account_easy_reconcile"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,date_base_on:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_date_base_on
|
||||
msgid "Date of reconciliation"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: help:easy.reconcile.advanced.bank_statement,analytic_account_id:0
|
||||
msgid "Analytic account for the write-off"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: view:account.easy.reconcile:0
|
||||
msgid "Advanced. Partner and Bank Statement"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: code:_description:0
|
||||
#: model:ir.model,name:account_advanced_reconcile_bank_statement.model_easy_reconcile_advanced
|
||||
#, python-format
|
||||
msgid "easy.reconcile.advanced"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,account_lost_id:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_account_lost_id
|
||||
msgid "Account Lost"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,write_off:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_write_off
|
||||
msgid "Write off allowed"
|
||||
msgstr ""
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_advanced_reconcile_bank_statement
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-05-27 08:36+0000\n"
|
||||
"PO-Revision-Date: 2014-05-27 08:36+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_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,filter:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_filter
|
||||
msgid "Filter"
|
||||
msgstr "Filtre"
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,account_id:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_account_id
|
||||
msgid "Account"
|
||||
msgstr "Compte"
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,partner_ids:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_partner_ids
|
||||
msgid "Restrict on partners"
|
||||
msgstr "Restriction sur les partenaires"
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: code:_description:0
|
||||
#: model:ir.model,name:account_advanced_reconcile_bank_statement.model_easy_reconcile_advanced_bank_statement
|
||||
#, python-format
|
||||
msgid "easy.reconcile.advanced.bank_statement"
|
||||
msgstr "easy.reconcile.advanced.bank_statement"
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: 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 "
|
||||
"reference is matched vs the debit entry bank statement 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 le nom du relevé bancaire des écritures de débit."
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,journal_id:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_journal_id
|
||||
msgid "Journal"
|
||||
msgstr "Journal"
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,account_profit_id:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_account_profit_id
|
||||
msgid "Account Profit"
|
||||
msgstr "Compte de produit"
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: code:_description:0
|
||||
#: model:ir.model,name:account_advanced_reconcile_bank_statement.model_account_easy_reconcile_method
|
||||
#, python-format
|
||||
msgid "reconcile method for account_easy_reconcile"
|
||||
msgstr "Méthode de lettrage pour le module account_easy_reconcile"
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,date_base_on:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_date_base_on
|
||||
msgid "Date of reconciliation"
|
||||
msgstr "Date de lettrage"
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: view:account.easy.reconcile:0
|
||||
msgid "Advanced. Partner and Bank Statement"
|
||||
msgstr "Avancé. Partenaire et Relevé Bancaire"
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: code:_description:0
|
||||
#: model:ir.model,name:account_advanced_reconcile_bank_statement.model_easy_reconcile_advanced
|
||||
#, python-format
|
||||
msgid "easy.reconcile.advanced"
|
||||
msgstr "easy.reconcile.advanced"
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,account_lost_id:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_account_lost_id
|
||||
msgid "Account Lost"
|
||||
msgstr "Compte de charge"
|
||||
|
||||
#. module: account_advanced_reconcile_bank_statement
|
||||
#: field:easy.reconcile.advanced.bank_statement,write_off:0
|
||||
#: model:ir.model.fields,field_description:account_advanced_reconcile_bank_statement.field_easy_reconcile_advanced_bank_statement_write_off
|
||||
msgid "Write off allowed"
|
||||
msgstr "Ecart autorisé"
|
||||
|
||||
@@ -30,16 +30,6 @@ class EasyReconcileAdvanced(orm.AbstractModel):
|
||||
""" Mandatory columns for move lines queries
|
||||
An extra column aliased as ``key`` should be defined
|
||||
in each query."""
|
||||
aml_cols = (
|
||||
'id',
|
||||
'debit',
|
||||
'credit',
|
||||
'date',
|
||||
'period_id',
|
||||
'ref',
|
||||
'name',
|
||||
'partner_id',
|
||||
'account_id',
|
||||
'move_id',
|
||||
'transaction_ref')
|
||||
return ["account_move_line.%s" % col for col in aml_cols]
|
||||
aml_cols = super(EasyReconcileAdvanced, self)._base_columns(rec)
|
||||
aml_cols.append('account_move_line.transaction_ref')
|
||||
return aml_cols
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import easy_reconcile
|
||||
import base_reconciliation
|
||||
import simple_reconciliation
|
||||
import easy_reconcile_history
|
||||
from . import easy_reconcile
|
||||
from . import base_reconciliation
|
||||
from . import simple_reconciliation
|
||||
from . import easy_reconcile_history
|
||||
from . import res_config
|
||||
|
||||
@@ -58,7 +58,9 @@ allows multiple lines and partial.
|
||||
"data": ["easy_reconcile.xml",
|
||||
"easy_reconcile_history_view.xml",
|
||||
"security/ir_rule.xml",
|
||||
"security/ir.model.access.csv"],
|
||||
"security/ir.model.access.csv",
|
||||
"res_config_view.xml",
|
||||
],
|
||||
'license': 'AGPL-3',
|
||||
"auto_install": False,
|
||||
'installable': False,
|
||||
|
||||
@@ -71,6 +71,7 @@ class EasyReconcileBase(orm.AbstractModel):
|
||||
'name',
|
||||
'partner_id',
|
||||
'account_id',
|
||||
'reconcile_partial_id',
|
||||
'move_id')
|
||||
return ["account_move_line.%s" % col for col in aml_cols]
|
||||
|
||||
@@ -78,10 +79,15 @@ class EasyReconcileBase(orm.AbstractModel):
|
||||
return "SELECT %s" % ', '.join(self._base_columns(rec))
|
||||
|
||||
def _from(self, rec, *args, **kwargs):
|
||||
return "FROM account_move_line"
|
||||
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):
|
||||
where = ("WHERE account_move_line.account_id = %s "
|
||||
"AND COALESCE(account_move_reconcile.type,'') <> 'manual' "
|
||||
"AND account_move_line.reconcile_id IS NULL ")
|
||||
# it would be great to use dict for params
|
||||
# but as we use _where_calc in _get_filter
|
||||
@@ -177,7 +183,7 @@ class EasyReconcileBase(orm.AbstractModel):
|
||||
cr, uid, rec, lines, rec.date_base_on, context=context)
|
||||
rec_ctx = dict(context, date_p=date)
|
||||
if below_writeoff:
|
||||
if sum_credit < sum_debit:
|
||||
if sum_credit > sum_debit:
|
||||
writeoff_account_id = rec.account_profit_id.id
|
||||
else:
|
||||
writeoff_account_id = rec.account_lost_id.id
|
||||
@@ -195,10 +201,42 @@ class EasyReconcileBase(orm.AbstractModel):
|
||||
context=rec_ctx)
|
||||
return True, True
|
||||
elif allow_partial:
|
||||
# Check if the group of move lines was already partially
|
||||
# reconciled and if all the lines were the same, in such
|
||||
# case, just skip the group and consider it as partially
|
||||
# reconciled (no change).
|
||||
if lines:
|
||||
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
|
||||
|
||||
# We need to give a writeoff_acc_id
|
||||
# in case we have a multi currency lines
|
||||
# to reconcile.
|
||||
# If amount in currency is equal between
|
||||
# lines to reconcile
|
||||
# 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
|
||||
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,
|
||||
type='manual',
|
||||
writeoff_acc_id=writeoff_account_id,
|
||||
writeoff_period_id=period_id,
|
||||
writeoff_journal_id=rec.journal_id.id,
|
||||
context=rec_ctx)
|
||||
return True, False
|
||||
return False, False
|
||||
|
||||
@@ -19,8 +19,14 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from datetime import datetime
|
||||
from openerp.osv import fields, orm
|
||||
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from openerp.tools.translate import _
|
||||
from openerp import pooler
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EasyReconcileOptions(orm.AbstractModel):
|
||||
@@ -60,6 +66,11 @@ class EasyReconcileOptions(orm.AbstractModel):
|
||||
'analytic_account_id': fields.many2one(
|
||||
'account.analytic.account', 'Analytic Account',
|
||||
help="Analytic account for the write-off"),
|
||||
'income_exchange_account_id': fields.many2one(
|
||||
'account.account', 'Gain Exchange Rate Account'),
|
||||
'expense_exchange_account_id': fields.many2one(
|
||||
'account.account', 'Loss Exchange Rate Account'),
|
||||
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
@@ -131,6 +142,7 @@ class AccountEasyReconcileMethod(orm.Model):
|
||||
class AccountEasyReconcile(orm.Model):
|
||||
|
||||
_name = 'account.easy.reconcile'
|
||||
_inherit = ['mail.thread']
|
||||
_description = 'account easy reconcile'
|
||||
|
||||
def _get_total_unrec(self, cr, uid, ids, name, arg, context=None):
|
||||
@@ -159,11 +171,16 @@ class AccountEasyReconcile(orm.Model):
|
||||
|
||||
def _last_history(self, cr, uid, ids, name, args, context=None):
|
||||
result = {}
|
||||
for history in self.browse(cr, uid, ids, context=context):
|
||||
result[history.id] = False
|
||||
if history.history_ids:
|
||||
# history is sorted by date desc
|
||||
result[history.id] = history.history_ids[0].id
|
||||
# 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.pool['easy.reconcile.history']
|
||||
for reconcile_id in ids:
|
||||
last_history = history_obj.search(
|
||||
cr, uid, [('easy_reconcile_id', '=', reconcile_id)],
|
||||
limit=1, order='date desc', context=context
|
||||
)
|
||||
result[reconcile_id] = last_history[0] if last_history else False
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
@@ -202,13 +219,19 @@ class AccountEasyReconcile(orm.Model):
|
||||
rec_method.account_profit_id.id),
|
||||
'analytic_account_id': (rec_method.analytic_account_id and
|
||||
rec_method.analytic_account_id.id),
|
||||
'income_exchange_account_id':
|
||||
(rec_method.income_exchange_account_id and
|
||||
rec_method.income_exchange_account_id.id),
|
||||
'expense_exchange_account_id':
|
||||
(rec_method.income_exchange_account_id and
|
||||
rec_method.income_exchange_account_id.id),
|
||||
'journal_id': (rec_method.journal_id and
|
||||
rec_method.journal_id.id),
|
||||
'date_base_on': rec_method.date_base_on,
|
||||
'filter': rec_method.filter}
|
||||
|
||||
def run_reconcile(self, cr, uid, ids, context=None):
|
||||
def find_reconcile_ids(fieldname, move_line_ids):
|
||||
def find_reconcile_ids(cr, fieldname, move_line_ids):
|
||||
if not move_line_ids:
|
||||
return []
|
||||
sql = ("SELECT DISTINCT " + fieldname +
|
||||
@@ -219,41 +242,75 @@ class AccountEasyReconcile(orm.Model):
|
||||
res = 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.
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
for rec in self.browse(cr, uid, ids, context=context):
|
||||
all_ml_rec_ids = []
|
||||
all_ml_partial_ids = []
|
||||
ctx = context.copy()
|
||||
ctx['commit_every'] = (
|
||||
rec.account.company_id.reconciliation_commit_every
|
||||
)
|
||||
if ctx['commit_every']:
|
||||
new_cr = pooler.get_db(cr.dbname).cursor()
|
||||
else:
|
||||
new_cr = cr
|
||||
try:
|
||||
all_ml_rec_ids = []
|
||||
all_ml_partial_ids = []
|
||||
|
||||
for method in rec.reconcile_method:
|
||||
rec_model = self.pool.get(method.name)
|
||||
auto_rec_id = rec_model.create(
|
||||
cr, uid,
|
||||
self._prepare_run_transient(
|
||||
cr, uid, method, context=context),
|
||||
context=context)
|
||||
for method in rec.reconcile_method:
|
||||
rec_model = self.pool.get(method.name)
|
||||
auto_rec_id = rec_model.create(
|
||||
new_cr, uid,
|
||||
self._prepare_run_transient(
|
||||
new_cr, uid, method, context=context),
|
||||
context=context)
|
||||
|
||||
ml_rec_ids, ml_partial_ids = rec_model.automatic_reconcile(
|
||||
cr, uid, auto_rec_id, context=context)
|
||||
ml_rec_ids, ml_partial_ids = rec_model.automatic_reconcile(
|
||||
new_cr, uid, auto_rec_id, context=ctx)
|
||||
|
||||
all_ml_rec_ids += ml_rec_ids
|
||||
all_ml_partial_ids += ml_partial_ids
|
||||
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)
|
||||
reconcile_ids = find_reconcile_ids(
|
||||
new_cr, 'reconcile_id', all_ml_rec_ids)
|
||||
partial_ids = find_reconcile_ids(
|
||||
new_cr, 'reconcile_partial_id', all_ml_partial_ids)
|
||||
|
||||
self.pool.get('easy.reconcile.history').create(
|
||||
cr,
|
||||
uid,
|
||||
{'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]},
|
||||
context=context)
|
||||
self.pool.get('easy.reconcile.history').create(new_cr, uid, {
|
||||
'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],
|
||||
}, context=context)
|
||||
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.value)
|
||||
message = "There was an error during reconciliation : %s" \
|
||||
% e.value
|
||||
self.message_post(cr, uid, rec.id,
|
||||
body=message, context=context)
|
||||
self.pool.get('easy.reconcile.history').create(new_cr, uid, {
|
||||
'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
|
||||
|
||||
def _no_history(self, cr, uid, rec, context=None):
|
||||
""" Raise an `osv.except_osv` error, supposed to
|
||||
""" Raise an `orm.except_orm` error, supposed to
|
||||
be called when there is no history on the reconciliation
|
||||
task.
|
||||
"""
|
||||
@@ -333,3 +390,30 @@ class AccountEasyReconcile(orm.Model):
|
||||
if not rec.last_history:
|
||||
self._no_history(cr, uid, rec, context=context)
|
||||
return rec.last_history.open_partial()
|
||||
|
||||
def run_scheduler(self, cr, uid, run_all=None, context=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 datetime.strptime(reconcile.last_history.date,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
else:
|
||||
return datetime.min
|
||||
|
||||
ids = self.search(cr, uid, [], context=context)
|
||||
assert ids, "No easy reconcile available"
|
||||
if run_all:
|
||||
self.run_reconcile(cr, uid, ids, context=context)
|
||||
return True
|
||||
reconciles = self.browse(cr, uid, ids, context=context)
|
||||
reconciles.sort(key=_get_date)
|
||||
older = reconciles[0]
|
||||
self.run_reconcile(cr, uid, [older.id], context=context)
|
||||
return True
|
||||
|
||||
@@ -71,6 +71,10 @@ The lines should have the same amount (with the write-off) and the same referenc
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@@ -129,6 +133,8 @@ The lines should have the same amount (with the write-off) and the same referenc
|
||||
<field name="write_off"/>
|
||||
<field name="account_lost_id" attrs="{'required':[('write_off','>',0)]}"/>
|
||||
<field name="account_profit_id" attrs="{'required':[('write_off','>',0)]}"/>
|
||||
<field name="income_exchange_account_id" groups="base.group_multi_currency"/>
|
||||
<field name="expense_exchange_account_id" groups="base.group_multi_currency"/>
|
||||
<field name="journal_id" attrs="{'required':[('write_off','>',0)]}"/>
|
||||
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="date_base_on"/>
|
||||
@@ -147,6 +153,8 @@ The lines should have the same amount (with the write-off) and the same referenc
|
||||
<field name="write_off"/>
|
||||
<field name="account_lost_id" attrs="{'required':[('write_off','>',0)]}"/>
|
||||
<field name="account_profit_id" attrs="{'required':[('write_off','>',0)]}"/>
|
||||
<field name="income_exchange_account_id" groups="base.group_multi_currency"/>
|
||||
<field name="expense_exchange_account_id" groups="base.group_multi_currency"/>
|
||||
<field name="journal_id" attrs="{'required':[('write_off','>',0)]}"/>
|
||||
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="date_base_on"/>
|
||||
@@ -161,4 +169,22 @@ The lines should have the same amount (with the write-off) and the same referenc
|
||||
parent="account.periodical_processing_reconciliation"/>
|
||||
|
||||
</data>
|
||||
|
||||
<data noupdate="1">
|
||||
|
||||
<record forcecreate="True" id="ir_cron_run_reconciliations" model="ir.cron">
|
||||
<field name="name">Do Automatic Reconciliations</field>
|
||||
<field eval="False" name="active"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="interval_number">3</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
<field eval="'account.easy.reconcile'" name="model"/>
|
||||
<field eval="'run_scheduler'" name="function"/>
|
||||
<field eval="'()'" name="args"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
</openerp>
|
||||
|
||||
@@ -53,7 +53,7 @@ class EasyReconcileHistory(orm.Model):
|
||||
_columns = {
|
||||
'easy_reconcile_id': fields.many2one(
|
||||
'account.easy.reconcile', 'Reconcile Profile', readonly=True),
|
||||
'date': fields.datetime('Run date', readonly=True),
|
||||
'date': fields.datetime('Run date', readonly=True, required=True),
|
||||
'reconcile_ids': fields.many2many(
|
||||
'account.move.reconcile',
|
||||
'account_move_reconcile_history_rel',
|
||||
@@ -62,28 +62,27 @@ class EasyReconcileHistory(orm.Model):
|
||||
'account.move.reconcile',
|
||||
'account_move_reconcile_history_partial_rel',
|
||||
string='Partial Reconciliations', readonly=True),
|
||||
'reconcile_line_ids':
|
||||
fields.function(
|
||||
'reconcile_line_ids': fields.function(
|
||||
_reconcile_line_ids,
|
||||
string='Reconciled Items',
|
||||
type='many2many',
|
||||
relation='account.move.line',
|
||||
readonly=True,
|
||||
multi='lines'),
|
||||
'partial_line_ids':
|
||||
fields.function(
|
||||
_reconcile_line_ids,
|
||||
string='Partially Reconciled Items',
|
||||
type='many2many',
|
||||
relation='account.move.line',
|
||||
readonly=True,
|
||||
multi='lines'),
|
||||
'company_id': fields.related('easy_reconcile_id', 'company_id',
|
||||
relation='res.company',
|
||||
type='many2one',
|
||||
string='Company',
|
||||
store=True,
|
||||
readonly=True),
|
||||
'partial_line_ids': fields.function(
|
||||
_reconcile_line_ids,
|
||||
string='Partially Reconciled Items',
|
||||
type='many2many',
|
||||
relation='account.move.line',
|
||||
readonly=True,
|
||||
multi='lines'),
|
||||
'company_id': fields.related(
|
||||
'easy_reconcile_id', 'company_id',
|
||||
relation='res.company',
|
||||
type='many2one',
|
||||
string='Company',
|
||||
store=True,
|
||||
readonly=True),
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -404,3 +404,24 @@ msgstr ""
|
||||
msgid "account easy reconcile"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_easy_reconcile
|
||||
#: field:account.easy.reconcile.method,expense_exchange_account_id:0
|
||||
#: field:easy.reconcile.base,expense_exchange_account_id:0
|
||||
#: field:easy.reconcile.options,expense_exchange_account_id:0
|
||||
#: field:easy.reconcile.simple,expense_exchange_account_id:0
|
||||
#: 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"
|
||||
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"
|
||||
msgstr ""
|
||||
|
||||
@@ -427,3 +427,25 @@ msgstr "easy.reconcile.simple.reference"
|
||||
#: model:ir.model,name:account_easy_reconcile.model_account_easy_reconcile
|
||||
msgid "account easy reconcile"
|
||||
msgstr "Lettrage automatisé"
|
||||
|
||||
#. module: account_easy_reconcile
|
||||
#: field:account.easy.reconcile.method,expense_exchange_account_id:0
|
||||
#: field:easy.reconcile.base,expense_exchange_account_id:0
|
||||
#: field:easy.reconcile.options,expense_exchange_account_id:0
|
||||
#: field:easy.reconcile.simple,expense_exchange_account_id:0
|
||||
#: 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"
|
||||
msgstr "Compte de perte de change"
|
||||
|
||||
#. 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"
|
||||
msgstr "Compte de gain de change"
|
||||
|
||||
59
__unported__/account_easy_reconcile/res_config.py
Normal file
59
__unported__/account_easy_reconcile/res_config.py
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
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."""),
|
||||
}
|
||||
24
__unported__/account_easy_reconcile/res_config_view.xml
Normal file
24
__unported__/account_easy_reconcile/res_config_view.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_account_config" model="ir.ui.view">
|
||||
<field name="name">account settings</field>
|
||||
<field name="model">account.config.settings</field>
|
||||
<field name="inherit_id" ref="account.view_account_config_settings"/>
|
||||
<field name="arch" type="xml">
|
||||
<separator string="eInvoicing & Payments" position="before">
|
||||
<separator string="Reconciliation"/>
|
||||
<group>
|
||||
<label for="id" string="Options"/>
|
||||
<div name="reconciliation_config">
|
||||
<div>
|
||||
<label for="reconciliation_commit_every"/>
|
||||
<field name="reconciliation_commit_every" class="oe_inline"/>
|
||||
</div>
|
||||
</div>
|
||||
</group>
|
||||
</separator>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -18,4 +18,5 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
#
|
||||
import statement
|
||||
from . import statement
|
||||
from . import res_partner_bank
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#
|
||||
# Authors: Laurent Mignon
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
# All Rights Reserved
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
#
|
||||
from openerp.osv.orm import Model
|
||||
|
||||
|
||||
class res_partner_bank(Model):
|
||||
_inherit = 'res.partner.bank'
|
||||
|
||||
def search_by_acc_number(self, cr, uid, acc_number, context=None):
|
||||
'''
|
||||
Try to find the Account Number using a 'like' operator to avoid
|
||||
problems with the input mask used to store the value.
|
||||
'''
|
||||
# first try with an exact match
|
||||
ids = self.search(cr,
|
||||
uid,
|
||||
[('acc_number', '=', acc_number)],
|
||||
context=context)
|
||||
if ids:
|
||||
return ids
|
||||
|
||||
cr.execute("""
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
res_partner_bank
|
||||
WHERE
|
||||
regexp_replace(acc_number,'([^[:alnum:]])', '','g')
|
||||
ilike
|
||||
regexp_replace(%s,'([^[:alnum:]])', '','g')
|
||||
""", (acc_number,))
|
||||
# apply security constraints by using the orm
|
||||
return self.search(cr, uid,
|
||||
[('id', 'in', [r[0] for r in cr.fetchall()])],
|
||||
context=context)
|
||||
@@ -23,8 +23,8 @@
|
||||
from openerp.tools.translate import _
|
||||
from openerp.osv.orm import Model
|
||||
from openerp.osv import fields
|
||||
from openerp.addons.account_statement_base_completion.statement import \
|
||||
ErrorTooManyPartner
|
||||
from openerp.addons.account_statement_base_completion.statement \
|
||||
import ErrorTooManyPartner
|
||||
|
||||
|
||||
class AccountStatementCompletionRule(Model):
|
||||
@@ -54,21 +54,25 @@ class AccountStatementCompletionRule(Model):
|
||||
partner_acc_number = st_line['partner_acc_number']
|
||||
if not partner_acc_number:
|
||||
return {}
|
||||
st_obj = self.pool.get('account.bank.statement.line')
|
||||
st_obj = self.pool['account.bank.statement.line']
|
||||
res = {}
|
||||
res_bank_obj = self.pool.get('res.partner.bank')
|
||||
ids = res_bank_obj.search(cr,
|
||||
uid,
|
||||
[('acc_number', '=', partner_acc_number)],
|
||||
context=context)
|
||||
res_bank_obj = self.pool['res.partner.bank']
|
||||
ids = res_bank_obj.search_by_acc_number(cr,
|
||||
uid,
|
||||
partner_acc_number,
|
||||
context=context)
|
||||
if len(ids) > 1:
|
||||
raise ErrorTooManyPartner(
|
||||
_('Line named "%s" (Ref:%s) was matched by more than one '
|
||||
'partner for account number "%s".') %
|
||||
(st_line['name'], st_line['ref'], partner_acc_number))
|
||||
raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched '
|
||||
'by more than one partner for account '
|
||||
'number "%s".') %
|
||||
(st_line['name'],
|
||||
st_line['ref'],
|
||||
partner_acc_number))
|
||||
if len(ids) == 1:
|
||||
partner = res_bank_obj.browse(
|
||||
cr, uid, ids[0], context=context).partner_id
|
||||
partner = res_bank_obj.browse(cr,
|
||||
uid,
|
||||
ids[0],
|
||||
context=context).partner_id
|
||||
res['partner_id'] = partner.id
|
||||
st_vals = st_obj.get_values_for_line(
|
||||
cr, uid, profile_id=st_line['profile_id'],
|
||||
|
||||
@@ -22,81 +22,102 @@
|
||||
from openerp.tests import common
|
||||
import time
|
||||
|
||||
ACC_NUMBER = "BE38733040385372"
|
||||
ACC_NUMBER = " BE38 7330 4038 5372 "
|
||||
|
||||
|
||||
class bankaccount_completion(common.TransactionCase):
|
||||
|
||||
def prepare(self):
|
||||
def setUp(self):
|
||||
super(bankaccount_completion, self).setUp()
|
||||
self.company_a = self.browse_ref('base.main_company')
|
||||
self.profile_obj = self.registry("account.statement.profile")
|
||||
self.st_obj = self.registry("account.bank.statement")
|
||||
self.acc_bk_stmt = self.registry("account.bank.statement")
|
||||
self.st_line_obj = self.registry("account.bank.statement.line")
|
||||
self.completion_rule_id = self.ref(
|
||||
'account_statement_bankaccount_completion.'
|
||||
'bank_statement_completion_rule_10')
|
||||
self.journal_id = self.registry("ir.model.data").get_object_reference(
|
||||
self.cr, self. uid, "account", "bank_journal")[1]
|
||||
self.completion_rule_id = \
|
||||
self.ref('account_statement_bankaccount_completion.'
|
||||
'bank_statement_completion_rule_10')
|
||||
self.journal_id = self.ref("account.bank_journal")
|
||||
self.partner_id = self.ref('base.main_partner')
|
||||
self.account_id = self.ref("account.a_recv")
|
||||
|
||||
# Create the profile
|
||||
self.account_id = self.registry("ir.model.data").get_object_reference(
|
||||
self.cr, self.uid, "account", "a_recv")[1]
|
||||
self.journal_id = self.registry("ir.model.data").get_object_reference(
|
||||
self.cr, self. uid, "account", "bank_journal")[1]
|
||||
self.profile_id = self.profile_obj.create(self.cr, self.uid, {
|
||||
"name": "TEST",
|
||||
"commission_account_id": self.account_id,
|
||||
"journal_id": self.journal_id,
|
||||
"rule_ids": [(6, 0, [self.completion_rule_id])]})
|
||||
# Create the completion rule
|
||||
|
||||
# Create a bank statement
|
||||
self.statement_id = self.st_obj.create(
|
||||
self.cr, self.uid, {
|
||||
"balance_end_real": 0.0,
|
||||
vals = {"balance_end_real": 0.0,
|
||||
"balance_start": 0.0,
|
||||
"date": time.strftime('%Y-%m-%d'),
|
||||
"journal_id": self.journal_id,
|
||||
"profile_id": self.profile_id
|
||||
})
|
||||
|
||||
# Create bank a statement line
|
||||
self.statement_line_id = self.st_line_obj.create(self.cr, self.uid, {
|
||||
'amount': 1000.0,
|
||||
'name': 'EXT001',
|
||||
'ref': 'My ref',
|
||||
'statement_id': self.statement_id,
|
||||
'partner_acc_number': ACC_NUMBER
|
||||
})
|
||||
"profile_id": self.profile_id,
|
||||
}
|
||||
self.statement_id = self.acc_bk_stmt.create(self.cr,
|
||||
self.uid,
|
||||
vals)
|
||||
|
||||
# Add a bank account number to the partner
|
||||
res_bank_obj = self.registry('res.partner.bank')
|
||||
res_bank_obj.create(self.cr, self.uid, {
|
||||
"state": "bank",
|
||||
"company_id": self.company_a.id,
|
||||
"partner_id": self.partner_id,
|
||||
"acc_number": ACC_NUMBER,
|
||||
"footer": True,
|
||||
"bank_name": "Reserve"
|
||||
})
|
||||
self.res_partner_bank_obj = self.registry('res.partner.bank')
|
||||
vals = {"state": "bank",
|
||||
"company_id": self.company_a.id,
|
||||
"partner_id": self.partner_id,
|
||||
"acc_number": ACC_NUMBER,
|
||||
"footer": True,
|
||||
"bank_name": "Reserve",
|
||||
}
|
||||
self.res_partner_bank_id = self.res_partner_bank_obj.create(self.cr,
|
||||
self.uid,
|
||||
vals)
|
||||
|
||||
def test_00(self):
|
||||
"""Test complete partner_id from bank account number
|
||||
|
||||
Test the automatic completion of the partner_id based on the account
|
||||
number associated to the
|
||||
statement line
|
||||
number associated to the statement line
|
||||
"""
|
||||
self.prepare()
|
||||
statement_line = self.st_line_obj.browse(self.cr, self.uid,
|
||||
self.statement_line_id)
|
||||
# before import, the
|
||||
self.assertFalse(
|
||||
statement_line.partner_id,
|
||||
"Partner_id must be blank before completion")
|
||||
statement_obj = self.st_obj.browse(self.cr, self.uid, self.statement_id)
|
||||
statement_obj.button_auto_completion()
|
||||
statement_line = self.st_line_obj.browse(self.cr, self.uid,
|
||||
self.statement_line_id)
|
||||
self.assertEquals(self.partner_id, statement_line.partner_id[
|
||||
'id'], "Missing expected partner id after completion")
|
||||
for bank_acc_number in [ACC_NUMBER, ACC_NUMBER.replace(" ", ""),
|
||||
ACC_NUMBER.replace(" ", "-")]:
|
||||
# check the completion for well formatted and not well
|
||||
# formatted account number
|
||||
self.res_partner_bank_obj.write(self.cr,
|
||||
self.uid,
|
||||
self.res_partner_bank_id,
|
||||
{"acc_number": bank_acc_number}
|
||||
)
|
||||
for acc_number in [ACC_NUMBER, ACC_NUMBER.replace(" ", ""),
|
||||
ACC_NUMBER.replace(" ", "-"),
|
||||
" BE38-7330 4038-5372 "]:
|
||||
vals = {'amount': 1000.0,
|
||||
'name': 'EXT001',
|
||||
'ref': 'My ref',
|
||||
'statement_id': self.statement_id,
|
||||
'partner_acc_number': acc_number
|
||||
}
|
||||
line_id = self.st_line_obj.create(self.cr, self.uid, vals)
|
||||
line = self.st_line_obj.browse(self.cr, self.uid, line_id)
|
||||
self.assertFalse(line.partner_id,
|
||||
'Partner_id must be blank before completion')
|
||||
statement_obj = self.acc_bk_stmt.browse(self.cr,
|
||||
self.uid,
|
||||
self.statement_id)
|
||||
statement_obj.button_auto_completion()
|
||||
line = self.st_line_obj.browse(self.cr, self.uid, line_id)
|
||||
self.assertEquals(self.partner_id, line.partner_id['id'],
|
||||
'Missing expected partner id after '
|
||||
'completion')
|
||||
vals = {'amount': 1000.0,
|
||||
'name': 'EXT001',
|
||||
'ref': 'My ref',
|
||||
'statement_id': self.statement_id,
|
||||
'partner_acc_number': 'BE38a7330.4038-5372.',
|
||||
}
|
||||
line_id = self.st_line_obj.create(self.cr, self.uid, vals)
|
||||
line = self.st_line_obj.browse(self.cr, self.uid, line_id)
|
||||
self.assertFalse(line.partner_id,
|
||||
'Partner_id must be blank before completion')
|
||||
statement_obj = self.acc_bk_stmt.browse(self.cr,
|
||||
self.uid,
|
||||
self.statement_id)
|
||||
statement_obj.button_auto_completion()
|
||||
line = self.st_line_obj.browse(self.cr, self.uid, line_id)
|
||||
self.assertFalse(line.partner_id.id)
|
||||
|
||||
@@ -26,13 +26,14 @@
|
||||
'maintainer': 'Camptocamp',
|
||||
'category': 'Finance',
|
||||
'complexity': 'normal',
|
||||
'depends': ['account_statement_ext'],
|
||||
'depends': ['account_statement_ext',
|
||||
'account_report_company'],
|
||||
'description': """
|
||||
The goal of this module is to improve the basic bank statement, help dealing
|
||||
with huge volume of reconciliation by providing basic rules to identify the
|
||||
partner of a bank statement line.
|
||||
Each bank statement profile can have its own rules to be applied according to a
|
||||
sequence order.
|
||||
Each bank statement profile can have its own rules to be applied according to
|
||||
a sequence order.
|
||||
|
||||
Some basic rules are provided in this module:
|
||||
|
||||
@@ -41,15 +42,15 @@
|
||||
2) Match from statement line label (based on partner name)
|
||||
3) Match from statement line reference (based on Invoice number)
|
||||
|
||||
You can easily override this module and add your own rules in your own one. The
|
||||
basic rules only fill in the partner, but you can use them to fill in any
|
||||
value of the line (in the future, we will add a rule to automatically match and
|
||||
reconcile the line).
|
||||
You can easily override this module and add your own rules in your own one.
|
||||
The basic rules only fill in the partner, but you can use them to fill in
|
||||
any value of the line (in the future, we will add a rule to automatically
|
||||
match and reconcile the line).
|
||||
|
||||
It adds as well a label on the bank statement line (on which the pre-define
|
||||
rules can match) and a char field on the partner called 'Bank Statement Label'.
|
||||
Using the pre-define rules, you will be able to match various labels for a
|
||||
partner.
|
||||
rules can match) and a char field on the partner called 'Bank Statement
|
||||
Label'. Using the pre-define rules, you will be able to match various
|
||||
labels for a partner.
|
||||
|
||||
The reference of the line is always used by the reconciliation process. We're
|
||||
supposed to copy there (or write manually) the matching string. This can be:
|
||||
@@ -59,9 +60,10 @@
|
||||
You can use it with our account_advanced_reconcile module to automatize the
|
||||
reconciliation process.
|
||||
|
||||
TODO: The rules that look for invoices to find out the partner should take back
|
||||
the payable / receivable account from there directly instead of retrieving it
|
||||
from partner properties !
|
||||
|
||||
TODO: The rules that look for invoices to find out the partner should take
|
||||
back the payable / receivable account from there directly instead of
|
||||
retrieving it from partner properties!
|
||||
""",
|
||||
'website': 'http://www.camptocamp.com',
|
||||
'data': [
|
||||
@@ -75,6 +77,7 @@
|
||||
'test/partner.yml',
|
||||
'test/invoice.yml',
|
||||
'test/supplier_invoice.yml',
|
||||
'test/refund.yml',
|
||||
'test/completion_test.yml'
|
||||
],
|
||||
'installable': False,
|
||||
|
||||
@@ -158,7 +158,7 @@ msgstr "Erreur système"
|
||||
#. module: account_statement_base_completion
|
||||
#: field:account.bank.statement.line,already_completed:0
|
||||
msgid "Auto-Completed"
|
||||
msgstr "Auto-Completé"
|
||||
msgstr "Auto-Complété"
|
||||
|
||||
#. module: account_statement_base_completion
|
||||
#: code:addons/account_statement_base_completion/statement.py:448
|
||||
@@ -170,7 +170,7 @@ msgstr "Erreur de bypass de l'ORM"
|
||||
#. module: account_statement_base_completion
|
||||
#: field:account.statement.completion.rule,sequence:0
|
||||
msgid "Sequence"
|
||||
msgstr "Séquence"
|
||||
msgstr "Séquence"
|
||||
|
||||
#. module: account_statement_base_completion
|
||||
#: code:addons/account_statement_base_completion/statement.py:280
|
||||
@@ -210,7 +210,7 @@ msgstr ""
|
||||
"Entrez les différentes descriptions/informations sur votre relevé bancaire "
|
||||
"séparées par un ';' Si l'une d'entre elles figure dans la ligne du "
|
||||
"relevé, le partenaire correspondant sera automatiquement retrouvé "
|
||||
"(A condition d'utiliser un règle de lettrage dans le profil)."
|
||||
"(à condition d'utiliser un règle de lettrage dans le profil)."
|
||||
|
||||
#. module: account_statement_base_completion
|
||||
#: model:ir.model,name:account_statement_base_completion.model_res_partner
|
||||
|
||||
@@ -32,8 +32,8 @@ class ResPartner(orm.Model):
|
||||
'bank_statement_label': fields.char(
|
||||
'Bank Statement Label', size=100,
|
||||
help="Enter the various label found on your bank statement "
|
||||
"separated by a ; If one of this label is include in the bank "
|
||||
"statement line, the partner will be automatically filled (as "
|
||||
"long as you use this method/rules in your statement "
|
||||
"profile)."),
|
||||
"separated by a ; If one of this label is include in the "
|
||||
"bank statement line, the partner will be automatically "
|
||||
"filled (as long as you use this method/rules in your "
|
||||
"statement profile)."),
|
||||
}
|
||||
|
||||
@@ -124,7 +124,9 @@ class AccountStatementCompletionRule(orm.Model):
|
||||
_order = "sequence asc"
|
||||
|
||||
def _get_functions(self, cr, uid, context=None):
|
||||
"""List of available methods for rules. Override this to add you own."""
|
||||
"""List of available methods for rules.
|
||||
|
||||
Override this to add you own."""
|
||||
return [
|
||||
('get_from_ref_and_invoice',
|
||||
'From line reference (based on customer invoice number)'),
|
||||
@@ -189,13 +191,7 @@ class AccountStatementCompletionRule(orm.Model):
|
||||
res = {}
|
||||
inv = self._find_invoice(cr, uid, line, inv_type, context=context)
|
||||
if inv:
|
||||
# FIXME use only commercial_partner_id of invoice in 7.1
|
||||
# this is for backward compatibility in 7.0 before
|
||||
# the refactoring of res.partner
|
||||
if hasattr(inv, 'commercial_partner_id'):
|
||||
partner_id = inv.commercial_partner_id.id
|
||||
else:
|
||||
partner_id = inv.partner_id.id
|
||||
partner_id = inv.commercial_partner_id.id
|
||||
res = {'partner_id': partner_id,
|
||||
'account_id': inv.account_id.id,
|
||||
'type': inv_type}
|
||||
@@ -225,8 +221,8 @@ class AccountStatementCompletionRule(orm.Model):
|
||||
# Should be private but data are initialised with no update XML
|
||||
def get_from_ref_and_invoice(self, cr, uid, line, context=None):
|
||||
"""Match the partner based on the invoice number and the reference of
|
||||
the statement line. Then, call the generic get_values_for_line method to
|
||||
complete other values. If more than one partner matched, raise the
|
||||
the statement line. Then, call the generic get_values_for_line method
|
||||
to complete other values. If more than one partner matched, raise the
|
||||
ErrorTooManyPartner error.
|
||||
|
||||
:param dict line: read of the concerned account.bank.statement.line
|
||||
@@ -242,11 +238,11 @@ class AccountStatementCompletionRule(orm.Model):
|
||||
# Should be private but data are initialised with no update XML
|
||||
def get_from_label_and_partner_field(self, cr, uid, st_line, context=None):
|
||||
"""
|
||||
Match the partner based on the label field of the statement line
|
||||
and the text defined in the 'bank_statement_label' field of the partner.
|
||||
Remember that we can have values separated with ; Then, call the generic
|
||||
get_values_for_line method to complete other values.
|
||||
If more than one partner matched, raise the ErrorTooManyPartner error.
|
||||
Match the partner based on the label field of the statement line and
|
||||
the text defined in the 'bank_statement_label' field of the partner.
|
||||
Remember that we can have values separated with ; Then, call the
|
||||
generic get_values_for_line method to complete other values. If more
|
||||
than one partner matched, raise the ErrorTooManyPartner error.
|
||||
|
||||
:param dict st_line: read of the concerned account.bank.statement.line
|
||||
:return:
|
||||
@@ -303,10 +299,10 @@ class AccountStatementCompletionRule(orm.Model):
|
||||
return res
|
||||
|
||||
def get_from_label_and_partner_name(self, cr, uid, st_line, context=None):
|
||||
"""Match the partner based on the label field of the statement line
|
||||
and the name of the partner. Then, call the generic get_values_for_line
|
||||
method to complete other values. If more than one partner matched, raise
|
||||
the ErrorTooManyPartner error.
|
||||
"""Match the partner based on the label field of the statement line and
|
||||
the name of the partner. Then, call the generic get_values_for_line
|
||||
method to complete other values. If more than one partner matched,
|
||||
raise the ErrorTooManyPartner error.
|
||||
|
||||
:param dict st_line: read of the concerned account.bank.statement.line
|
||||
:return:
|
||||
@@ -333,7 +329,7 @@ class AccountStatementCompletionRule(orm.Model):
|
||||
# to:
|
||||
# http://www.postgresql.org/docs/9.0/static/functions-matching.html
|
||||
# in chapter 9.7.3.6. Limits and Compatibility
|
||||
sql = """
|
||||
sql = r"""
|
||||
SELECT id FROM (
|
||||
SELECT id,
|
||||
regexp_matches(%s,
|
||||
@@ -386,9 +382,9 @@ class AccountStatement(orm.Model):
|
||||
|
||||
class AccountStatementLine(orm.Model):
|
||||
"""
|
||||
Add sparse field on the statement line to allow to store all the
|
||||
bank infos that are given by a bank/office. You can then add you own in your
|
||||
module. The idea here is to store all bank/office infos in the
|
||||
Add sparse field on the statement line to allow to store all the bank infos
|
||||
that are given by a bank/office. You can then add you own in your module.
|
||||
The idea here is to store all bank/office infos in the
|
||||
additionnal_bank_fields serialized field when importing the file. If many
|
||||
values, add a tab in the bank statement line to store your specific one.
|
||||
Have a look in account_statement_base_import module to see how we've done
|
||||
@@ -449,7 +445,8 @@ class AccountStatementLine(orm.Model):
|
||||
statement_line_obj = self.pool['account.bank.statement.line']
|
||||
model_cols = statement_line_obj._columns
|
||||
avail = [
|
||||
k for k, col in model_cols.iteritems() if not hasattr(col, '_fnct')]
|
||||
k for k, col in model_cols.iteritems() if not hasattr(col, '_fnct')
|
||||
]
|
||||
keys = [k for k in statement_store[0].keys() if k in avail]
|
||||
# add sparse fields..
|
||||
if include_serializable:
|
||||
@@ -635,7 +632,8 @@ class AccountBankStatement(orm.Model):
|
||||
st += ''.join(traceback.format_tb(trbk, 30))
|
||||
_logger.error(st)
|
||||
if res:
|
||||
# stat_line_obj.write(cr, uid, [line.id], vals, context=ctx)
|
||||
# stat_line_obj.write(cr, uid, [line.id], vals,
|
||||
# context=ctx)
|
||||
try:
|
||||
stat_line_obj._update_line(
|
||||
cr, uid, res, context=context)
|
||||
|
||||
@@ -38,6 +38,15 @@
|
||||
ref: T2S12345
|
||||
date: '2013-12-19'
|
||||
amount: -65.0
|
||||
-
|
||||
I create a statement line for a CR
|
||||
-
|
||||
!record {model: account.bank.statement.line, id: statement_line_cr}:
|
||||
name: Test autocompletion based on Customer Refund Number
|
||||
statement_id: statement_test1
|
||||
ref: CR0001
|
||||
date: '2013-12-19'
|
||||
amount: -210.0
|
||||
-
|
||||
I create a statement line for the Partner Name
|
||||
-
|
||||
@@ -76,12 +85,18 @@
|
||||
!assert {model: account.bank.statement.line, id: statement_line_si, string: Check completion by SI number}:
|
||||
- partner_id.id == _ref("base.res_partner_17")
|
||||
-
|
||||
Line 3. I check that the partner name has been recognised.
|
||||
Line 3. I expect the Customer refund number to be recognised. It should be
|
||||
the commercial partner, and not the regular partner.
|
||||
-
|
||||
!assert {model: account.bank.statement.line, id: statement_line_cr, string: Check completion by CR number and commercial partner}:
|
||||
- partner_id.id == _ref("base.res_partner_12")
|
||||
-
|
||||
Line 4. I check that the partner name has been recognised.
|
||||
-
|
||||
!assert {model: account.bank.statement.line, id: statement_line_partner_name, string: Check completion by partner name}:
|
||||
- partner_id.name == 'Vauxoo'
|
||||
-
|
||||
Line 4. I check that the partner special label has been recognised.
|
||||
Line 5. I check that the partner special label has been recognised.
|
||||
-
|
||||
!assert {model: account.bank.statement.line, id: statement_line_partner_label, string: Check completion by partner label}:
|
||||
- partner_id.id == _ref("base.res_partner_6")
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
-
|
||||
I create a "child" partner, to use in the invoice
|
||||
(and have a different commercial_partner_id than itself)
|
||||
-
|
||||
!record {model: res.partner, id: res_partner_12_child}:
|
||||
name: Child Partner
|
||||
supplier: False
|
||||
customer: True
|
||||
is_company: False
|
||||
parent_id: base.res_partner_12
|
||||
-
|
||||
I create a customer refund to be found by the completion.
|
||||
-
|
||||
!record {model: account.invoice, id: refund_for_completion_1}:
|
||||
account_id: account.a_pay
|
||||
company_id: base.main_company
|
||||
currency_id: base.EUR
|
||||
internal_number: CR0001
|
||||
invoice_line:
|
||||
- account_id: account.a_expense
|
||||
name: '[PCSC234] PC Assemble SC234'
|
||||
price_unit: 210.0
|
||||
quantity: 1.0
|
||||
product_id: product.product_product_3
|
||||
uos_id: product.product_uom_unit
|
||||
journal_id: account.expenses_journal
|
||||
partner_id: res_partner_12_child
|
||||
type: 'out_refund'
|
||||
reference_type: none
|
||||
-
|
||||
I confirm the refund
|
||||
-
|
||||
!workflow {model: account.invoice, action: invoice_open, ref: refund_for_completion_1}
|
||||
-
|
||||
I check that the refund state is "Open"
|
||||
-
|
||||
!assert {model: account.invoice, id: refund_for_completion_1}:
|
||||
- state == 'open'
|
||||
-
|
||||
I check that it is given the number "CR0001"
|
||||
-
|
||||
!assert {model: account.invoice, id: refund_for_completion_1, string: Check CI number}:
|
||||
- number == 'CR0001'
|
||||
@@ -65,8 +65,8 @@ class base_completion(common.TransactionCase):
|
||||
|
||||
def test_name_completion(self):
|
||||
"""Test complete partner_id from statement line label
|
||||
Test the automatic completion of the partner_id based if the name of the
|
||||
partner appears in the statement line label
|
||||
Test the automatic completion of the partner_id based if the name of
|
||||
the partner appears in the statement line label
|
||||
"""
|
||||
self.completion_rule_id = self.ref(
|
||||
'account_statement_base_completion.'
|
||||
@@ -89,7 +89,8 @@ class base_completion(common.TransactionCase):
|
||||
|
||||
for case in NAMES_COMPLETION_CASES:
|
||||
self.partner_obj.write(
|
||||
self.cr, self.uid, self.partner_id, {'name': case.partner_name})
|
||||
self.cr, self.uid, self.partner_id, {'name': case.partner_name}
|
||||
)
|
||||
statement_line_id = self.account_bank_statement_line_obj.create(
|
||||
self.cr, self.uid, {
|
||||
'amount': 1000.0,
|
||||
@@ -116,5 +117,6 @@ class base_completion(common.TransactionCase):
|
||||
else:
|
||||
self.assertNotEquals(
|
||||
self.partner_id, statement_line.partner_id['id'],
|
||||
"Partner id should be empty after completion(partner_name: "
|
||||
"%s, line_name: %s)" % (case.partner_name, case.line_label))
|
||||
"Partner id should be empty after completion "
|
||||
"(partner_name: %s, line_name: %s)"
|
||||
% (case.partner_name, case.line_label))
|
||||
|
||||
@@ -18,6 +18,6 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import parser
|
||||
import wizard
|
||||
import statement
|
||||
from . import parser
|
||||
from . import wizard
|
||||
from . import statement
|
||||
|
||||
@@ -57,8 +57,8 @@
|
||||
|
||||
The goal is here to populate the statement lines of a bank statement with the
|
||||
infos that the bank or office give you. Fell free to inherit from this module
|
||||
to add your own format. Then, if you need to complete data from there, add your
|
||||
own account_statement_*_completion module and implement the needed rules.
|
||||
to add your own format. Then, if you need to complete data from there, add
|
||||
your own account_statement_*_completion module and implement the needed rules.
|
||||
""",
|
||||
'website': 'http://www.camptocamp.com',
|
||||
'data': [
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from parser import new_bank_statement_parser
|
||||
from parser import BankStatementImportParser
|
||||
import file_parser
|
||||
import generic_file_parser
|
||||
from .parser import new_bank_statement_parser
|
||||
from .parser import BankStatementImportParser
|
||||
from . import file_parser
|
||||
from . import generic_file_parser
|
||||
|
||||
@@ -21,8 +21,8 @@ from openerp.tools.translate import _
|
||||
from openerp.osv.orm import except_orm
|
||||
import tempfile
|
||||
import datetime
|
||||
from parser import BankStatementImportParser
|
||||
from parser import UnicodeDictReader
|
||||
from .parser import BankStatementImportParser
|
||||
from .parser import UnicodeDictReader
|
||||
try:
|
||||
import xlrd
|
||||
except:
|
||||
@@ -41,12 +41,12 @@ class FileParser(BankStatementImportParser):
|
||||
"""
|
||||
|
||||
def __init__(self, parse_name, ftype='csv', extra_fields=None, header=None,
|
||||
**kwargs):
|
||||
dialect=None, **kwargs):
|
||||
"""
|
||||
:param char: parse_name: The name of the parser
|
||||
:param char: ftype: extension of the file (could be csv, xls or
|
||||
xlsx)
|
||||
:param dict: extra_fields: extra fields to add to the conversion
|
||||
:param dict: extra_fields: extra fields to put into the conversion
|
||||
dict. In the format {fieldname: fieldtype}
|
||||
:param list: header : specify header fields if the csv file has no
|
||||
header
|
||||
@@ -58,19 +58,13 @@ class FileParser(BankStatementImportParser):
|
||||
raise except_orm(
|
||||
_('User Error'),
|
||||
_('Invalid file type %s. Please use csv, xls or xlsx') % ftype)
|
||||
self.conversion_dict = {
|
||||
'ref': unicode,
|
||||
'label': unicode,
|
||||
'date': datetime.datetime,
|
||||
'amount': float_or_zero,
|
||||
}
|
||||
if extra_fields:
|
||||
self.conversion_dict.update(extra_fields)
|
||||
self.conversion_dict = extra_fields
|
||||
self.keys_to_validate = self.conversion_dict.keys()
|
||||
self.fieldnames = header
|
||||
self._datemode = 0 # used only for xls documents,
|
||||
# 0 means Windows mode (1900 based dates).
|
||||
# Set in _parse_xls, from the contents of the file
|
||||
self.dialect = dialect
|
||||
|
||||
def _custom_format(self, *args, **kwargs):
|
||||
"""No other work on data are needed in this parser."""
|
||||
@@ -118,7 +112,8 @@ class FileParser(BankStatementImportParser):
|
||||
csv_file.write(self.filebuffer)
|
||||
csv_file.flush()
|
||||
with open(csv_file.name, 'rU') as fobj:
|
||||
reader = UnicodeDictReader(fobj, fieldnames=self.fieldnames)
|
||||
reader = UnicodeDictReader(fobj, fieldnames=self.fieldnames,
|
||||
dialect=self.dialect)
|
||||
return list(reader)
|
||||
|
||||
def _parse_xls(self):
|
||||
@@ -181,9 +176,9 @@ class FileParser(BankStatementImportParser):
|
||||
except Exception as err:
|
||||
raise except_orm(
|
||||
_("Date format is not valid"),
|
||||
_("Please modify the cell formatting to date format"
|
||||
" for column: %s value: %s\n Please check the "
|
||||
"line with ref: %s\n \n Detail: %s") %
|
||||
_("Please modify the cell formatting to date "
|
||||
"format for column: %s value: %s\n Please check "
|
||||
"the line with ref: %s\n \n Detail: %s") %
|
||||
(rule, line.get(rule, _('Missing')),
|
||||
line.get('ref', line), repr(err)))
|
||||
else:
|
||||
|
||||
@@ -19,18 +19,31 @@
|
||||
##############################################################################
|
||||
|
||||
import datetime
|
||||
from file_parser import FileParser
|
||||
from .file_parser import FileParser
|
||||
from openerp.addons.account_statement_base_import.parser.file_parser import (
|
||||
float_or_zero
|
||||
)
|
||||
from openerp.tools import ustr
|
||||
|
||||
|
||||
class GenericFileParser(FileParser):
|
||||
"""Standard parser that use a define format in csv or xls to import into a
|
||||
bank statement. This is mostely an example of how to proceed to create a new
|
||||
parser, but will also be useful as it allow to import a basic flat file.
|
||||
bank statement. This is mostely an example of how to proceed to create a
|
||||
new parser, but will also be useful as it allow to import a basic flat
|
||||
file.
|
||||
"""
|
||||
|
||||
def __init__(self, parse_name, ftype='csv', **kwargs):
|
||||
conversion_dict = {
|
||||
'ref': ustr,
|
||||
'label': ustr,
|
||||
'date': datetime.datetime,
|
||||
'amount': float_or_zero,
|
||||
}
|
||||
super(GenericFileParser, self).__init__(
|
||||
parse_name, ftype=ftype, **kwargs)
|
||||
parse_name, ftype=ftype,
|
||||
extra_fields=conversion_dict,
|
||||
**kwargs)
|
||||
|
||||
@classmethod
|
||||
def parser_for(cls, parser_name):
|
||||
@@ -42,9 +55,9 @@ class GenericFileParser(FileParser):
|
||||
def get_st_line_vals(self, line, *args, **kwargs):
|
||||
"""
|
||||
This method must return a dict of vals that can be passed to create
|
||||
method of statement line in order to record it. It is the responsibility
|
||||
of every parser to give this dict of vals, so each one can implement his
|
||||
own way of recording the lines.
|
||||
method of statement line in order to record it. It is the
|
||||
responsibility of every parser to give this dict of vals, so each one
|
||||
can implement his own way of recording the lines.
|
||||
:param: line: a dict of vals that represent a line of
|
||||
result_row_list
|
||||
:return: dict of values to give to the create method of statement
|
||||
|
||||
@@ -29,11 +29,16 @@ def UnicodeDictReader(utf8_data, **kwargs):
|
||||
pos = utf8_data.tell()
|
||||
sample_data = utf8_data.read(2048)
|
||||
utf8_data.seek(pos)
|
||||
dialect = sniffer.sniff(sample_data, delimiters=',;\t')
|
||||
if not kwargs.get('dialect'):
|
||||
dialect = sniffer.sniff(sample_data, delimiters=',;\t')
|
||||
del kwargs['dialect']
|
||||
else:
|
||||
dialect = kwargs.pop('dialect')
|
||||
csv_reader = csv.DictReader(utf8_data, dialect=dialect, **kwargs)
|
||||
for row in csv_reader:
|
||||
yield dict([(key, unicode(value, 'utf-8')) for key, value in
|
||||
row.iteritems()])
|
||||
yield dict([(unicode(key or '', 'utf-8'),
|
||||
unicode(value or '', 'utf-8'))
|
||||
for key, value in row.iteritems()])
|
||||
|
||||
|
||||
class BankStatementImportParser(object):
|
||||
@@ -48,8 +53,8 @@ class BankStatementImportParser(object):
|
||||
def __init__(self, profile, *args, **kwargs):
|
||||
# The name of the parser as it will be called
|
||||
self.parser_name = profile.import_type
|
||||
# The result as a list of row. One row per line of data in the file, but
|
||||
# not the commission one !
|
||||
# The result as a list of row. One row per line of data in the file,
|
||||
# but not the commission one!
|
||||
self.result_row_list = None
|
||||
# The file buffer on which to work on
|
||||
self.filebuffer = None
|
||||
@@ -128,9 +133,9 @@ class BankStatementImportParser(object):
|
||||
|
||||
def get_st_line_vals(self, line, *args, **kwargs):
|
||||
"""Implement a method in your parser that must return a dict of vals
|
||||
that can be passed to create method of statement line in order to record
|
||||
it. It is the responsibility of every parser to give this dict of vals,
|
||||
so each one can implement his own way of recording the lines.
|
||||
that can be passed to create method of statement line in order to
|
||||
record it. It is the responsibility of every parser to give this dict
|
||||
of vals, so each one can implement his own way of recording the lines.
|
||||
|
||||
:param: line: a dict of vals that represent a line of result_row_list
|
||||
:return: dict of values to give to the create method of statement line,
|
||||
|
||||
@@ -23,7 +23,7 @@ import traceback
|
||||
from openerp.tools.translate import _
|
||||
import datetime
|
||||
from openerp.osv import fields, orm
|
||||
from parser import new_bank_statement_parser
|
||||
from .parser import new_bank_statement_parser
|
||||
from openerp.tools.config import config
|
||||
|
||||
|
||||
@@ -74,13 +74,13 @@ class AccountStatementProfil(orm.Model):
|
||||
statement ID
|
||||
:param: context: global context
|
||||
"""
|
||||
pass
|
||||
|
||||
def write_logs_after_import(self, cr, uid, ids, statement_id, num_lines,
|
||||
context):
|
||||
"""Write the log in the logger
|
||||
|
||||
:param int/long statement_id: ID of the concerned account.bank.statement
|
||||
:param int/long statement_id: ID of the concerned
|
||||
account.bank.statement
|
||||
:param int/long num_lines: Number of line that have been parsed
|
||||
:return: True
|
||||
"""
|
||||
@@ -102,7 +102,8 @@ class AccountStatementProfil(orm.Model):
|
||||
|
||||
:param dict of vals from parser for account.bank.statement.line
|
||||
(called by parser.get_st_line_vals)
|
||||
:param int/long statement_id: ID of the concerned account.bank.statement
|
||||
:param int/long statement_id: ID of the concerned
|
||||
account.bank.statement
|
||||
:return: dict of vals that will be passed to create method of
|
||||
statement line.
|
||||
"""
|
||||
@@ -133,7 +134,7 @@ class AccountStatementProfil(orm.Model):
|
||||
"""
|
||||
vals = {'profile_id': profile_id}
|
||||
vals.update(parser.get_st_vals())
|
||||
if not vals.get('balance_start'):
|
||||
if vals.get('balance_start') is None:
|
||||
# Get starting balance from journal balance if parser doesn't
|
||||
# fill this data, simulating the manual flow
|
||||
statement_obj = self.pool['account.bank.statement']
|
||||
@@ -173,8 +174,8 @@ class AccountStatementProfil(orm.Model):
|
||||
ftype="csv", context=None):
|
||||
"""Create a bank statement with the given profile and parser. It will
|
||||
fullfill the bank statement with the values of the file providen, but
|
||||
will not complete data (like finding the partner, or the right account).
|
||||
This will be done in a second step with the completion rules.
|
||||
will not complete data (like finding the partner, or the right
|
||||
account). This will be done in a second step with the completion rules.
|
||||
|
||||
:param prof : The profile used to import the file
|
||||
:param parser: the parser
|
||||
|
||||
@@ -17,4 +17,4 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import import_statement
|
||||
from . import import_statement
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
###############################################################################
|
||||
"""Account Statement Cancel Line."""
|
||||
|
||||
import statement # noqa
|
||||
import statement_line # noqa
|
||||
import wizard # noqa
|
||||
from . import statement # noqa
|
||||
from . import statement_line # noqa
|
||||
from . import wizard # noqa
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
name: line1
|
||||
statement_id: statement_test
|
||||
ref: ref1
|
||||
date: '2014-01-20'
|
||||
date: !eval "'%s-01-20' %(datetime.now().year)"
|
||||
amount: 100.0
|
||||
-
|
||||
I create a second statement line
|
||||
@@ -31,7 +31,7 @@
|
||||
name: line2
|
||||
statement_id: statement_test
|
||||
ref: ref2
|
||||
date: '2014-01-25'
|
||||
date: !eval "'%s-01-25' %(datetime.now().year)"
|
||||
amount: 200.0
|
||||
-
|
||||
I check that the state of the statement is "Draft"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
name: line11
|
||||
statement_id: statement_test_10
|
||||
ref: ref11
|
||||
date: '2014-01-20'
|
||||
date: !eval "'%s-01-20' %(datetime.now().year)"
|
||||
amount: 100.0
|
||||
-
|
||||
I create a second statement line
|
||||
@@ -32,7 +32,7 @@
|
||||
name: line12
|
||||
statement_id: statement_test_10
|
||||
ref: ref12
|
||||
date: '2014-01-25'
|
||||
date: !eval "'%s-01-25' %(datetime.now().year)"
|
||||
amount: 200.0
|
||||
-
|
||||
Now I confirm only the first statement line
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
name: line1
|
||||
statement_id: statement_test3
|
||||
ref: line1
|
||||
date: '2014-01-20'
|
||||
date: !eval "'%s-01-20' %(datetime.now().year)"
|
||||
amount: 10.0
|
||||
-
|
||||
Now I confirm the statement line. That should not pass the balance check
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
name: line1
|
||||
statement_id: statement_test4
|
||||
ref: line1
|
||||
date: '2014-01-20'
|
||||
date: !eval "'%s-01-20' %(datetime.now().year)"
|
||||
amount: 10.0
|
||||
-
|
||||
Now I confirm the statement line
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
###############################################################################
|
||||
"""Wizard for asking the confirmation when some move is reconciled."""
|
||||
|
||||
import cancel_statement # noqa
|
||||
import cancel_statement_line # noqa
|
||||
from . import cancel_statement # noqa
|
||||
from . import cancel_statement_line # noqa
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import commission
|
||||
from . import commission
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
'account_statement_base_import'
|
||||
],
|
||||
'description': """
|
||||
This module brings commission support to bank statement imports. It computes the
|
||||
sum of a commission field on each transaction and creates a statement entry for
|
||||
it.
|
||||
This module brings commission support to bank statement imports. It computes
|
||||
the sum of a commission field on each transaction and creates a statement
|
||||
entry for it.
|
||||
""",
|
||||
'website': 'http://www.camptocamp.com',
|
||||
'data': [
|
||||
|
||||
@@ -24,7 +24,8 @@ class AccountStatementProfil(orm.Model):
|
||||
commission_analytic_id = profile.commission_analytic_id.id
|
||||
comm_values = {
|
||||
'name': 'IN ' + _('Commission line'),
|
||||
'date': parser.get_st_vals().get('date') or datetime.datetime.now(),
|
||||
'date': parser.get_st_vals().get('date') or
|
||||
datetime.datetime.now(),
|
||||
'amount': global_commission_amount,
|
||||
'partner_id': partner_id,
|
||||
'type': 'general',
|
||||
@@ -32,8 +33,8 @@ class AccountStatementProfil(orm.Model):
|
||||
'account_id': commission_account_id,
|
||||
'ref': 'commission',
|
||||
'analytic_account_id': commission_analytic_id,
|
||||
# !! We set the already_completed so auto-completion will not update
|
||||
# those values!
|
||||
# !! We set the already_completed so auto-completion will not
|
||||
# update those values!
|
||||
'already_completed': True,
|
||||
}
|
||||
st_obj = self.pool['account.bank.statement.line']
|
||||
|
||||
@@ -92,7 +92,7 @@ class AccountStatementCompletionRule(orm.Model):
|
||||
ON
|
||||
st_l.statement_id = s.id
|
||||
WHERE
|
||||
st_l.name ~* l.label
|
||||
(st_l.name ~* l.label OR st_l.ref ~* l.label)
|
||||
AND
|
||||
l.profile_id = s.profile_id
|
||||
AND
|
||||
@@ -125,8 +125,8 @@ class AccountStatementLabel(orm.Model):
|
||||
'label': fields.char('Bank Statement Label', size=100),
|
||||
'account_id': fields.many2one('account.account', 'Account',
|
||||
required=True,
|
||||
help='Account corresponding to the label '
|
||||
'for a given partner'),
|
||||
help='Account corresponding to the '
|
||||
'label for a given partner'),
|
||||
'company_id': fields.related('account_id', 'company_id',
|
||||
type='many2one',
|
||||
relation='res.company',
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import statement
|
||||
import report
|
||||
import account
|
||||
import voucher
|
||||
from . import statement
|
||||
from . import report
|
||||
from . import account
|
||||
from . import voucher
|
||||
|
||||
@@ -45,8 +45,8 @@
|
||||
Features:
|
||||
|
||||
1) Improve the bank statement: allows to define profiles (for each Office or
|
||||
Bank). The bank statement will then generate the entries based on some criteria
|
||||
chosen in the selected profile. You can setup on the profile:
|
||||
Bank). The bank statement will then generate the entries based on some
|
||||
criteria chosen in the selected profile. You can setup on the profile:
|
||||
|
||||
- the journal to use
|
||||
- use balance check or not
|
||||
|
||||
@@ -23,4 +23,4 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import bank_statement_report
|
||||
from . import bank_statement_report
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#
|
||||
##############################################################################
|
||||
import openerp.addons.account.account_bank_statement as stat_mod
|
||||
from openerp.osv import fields, orm
|
||||
from openerp.osv import fields, orm, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
@@ -52,8 +52,8 @@ class AccountStatementProfile(orm.Model):
|
||||
'name': fields.char('Name', required=True),
|
||||
'sequence': fields.integer(
|
||||
'Sequence',
|
||||
help="Gives a sequence in lists, the first profile will be used as "
|
||||
"default"),
|
||||
help="Gives a sequence in lists, the first profile will be used "
|
||||
"as default"),
|
||||
'partner_id': fields.many2one(
|
||||
'res.partner',
|
||||
'Bank/Payment Office partner',
|
||||
@@ -144,7 +144,8 @@ class AccountBankStatement(orm.Model):
|
||||
profile_obj = self.pool['account.statement.profile']
|
||||
user = user_obj.browse(cr, uid, uid, context=context)
|
||||
profile_ids = profile_obj.search(
|
||||
cr, uid, [('company_id', '=', user.company_id.id)], context=context)
|
||||
cr, uid, [('company_id', '=', user.company_id.id)], context=context
|
||||
)
|
||||
return profile_ids[0] if profile_ids else False
|
||||
|
||||
def _get_statement_from_profile(self, cr, uid, profile_ids, context=None):
|
||||
@@ -304,7 +305,8 @@ class AccountBankStatement(orm.Model):
|
||||
line if different from the statement line account ID
|
||||
:param int/long analytic_id: ID of analytic account to put on the
|
||||
move line
|
||||
:param int/long partner_id: ID of the partner to put on the move line
|
||||
:param int/long partner_id: ID of the partner to put on the move
|
||||
line
|
||||
:return: dict of value to create() the account.move.line
|
||||
"""
|
||||
if context is None:
|
||||
@@ -420,7 +422,7 @@ class AccountBankStatement(orm.Model):
|
||||
self.create_move_from_st_line(
|
||||
cr, uid, st_line.id, company_currency_id,
|
||||
st_line_number, context)
|
||||
except orm.except_orm, exc:
|
||||
except (orm.except_orm, osv.except_osv) as exc:
|
||||
msg = "Line ID %s with ref %s had following error: %s" % (
|
||||
st_line.id, st_line.ref, exc.value)
|
||||
errors_stack.append(msg)
|
||||
@@ -445,7 +447,7 @@ class AccountBankStatement(orm.Model):
|
||||
def get_account_for_counterpart(self, cr, uid, amount, account_receivable,
|
||||
account_payable):
|
||||
"""For backward compatibility."""
|
||||
account_id, type = self.get_account_and_type_for_counterpart(
|
||||
account_id, account_type = self.get_account_and_type_for_counterpart(
|
||||
cr, uid, amount, account_receivable, account_payable)
|
||||
return account_id
|
||||
|
||||
@@ -496,10 +498,10 @@ class AccountBankStatement(orm.Model):
|
||||
self, cr, uid, amount, account_receivable, account_payable,
|
||||
partner_id=False):
|
||||
"""
|
||||
Give the amount, payable and receivable account (that can be found using
|
||||
get_default_pay_receiv_accounts method) and receive the one to use. This
|
||||
method should be use when there is no other way to know which one to
|
||||
take. The rules are:
|
||||
Give the amount, payable and receivable account (that can be found
|
||||
using get_default_pay_receiv_accounts method) and receive the one to
|
||||
use. This method should be use when there is no other way to know which
|
||||
one to take. The rules are:
|
||||
- If the customer checkbox is checked on the found partner, type and
|
||||
account will be customer and receivable
|
||||
- If the supplier checkbox is checked on the found partner, type and
|
||||
@@ -606,7 +608,7 @@ class AccountBankStatementLine(orm.Model):
|
||||
local_context['account_period_prefer_normal'] = True
|
||||
try:
|
||||
periods = period_obj.find(cr, uid, dt=date, context=local_context)
|
||||
except orm.except_orm:
|
||||
except (orm.except_orm, osv.except_osv):
|
||||
# if no period defined, we are certainly at installation time
|
||||
return False
|
||||
return periods and periods[0] or False
|
||||
@@ -617,7 +619,8 @@ class AccountBankStatementLine(orm.Model):
|
||||
_columns = {
|
||||
# Set them as required + 64 char instead of 32
|
||||
'ref': fields.char('Reference', size=64, required=True),
|
||||
'period_id': fields.many2one('account.period', 'Period', required=True),
|
||||
'period_id': fields.many2one(
|
||||
'account.period', 'Period', required=True),
|
||||
}
|
||||
_defaults = {
|
||||
'period_id': _get_period,
|
||||
@@ -732,8 +735,8 @@ class AccountBankStatementLine(orm.Model):
|
||||
'voucher_id': False}}
|
||||
return {'value': {'type': line_type}}
|
||||
|
||||
def onchange_type(self, cr, uid, line_id, partner_id, line_type, profile_id,
|
||||
context=None):
|
||||
def onchange_type(self, cr, uid, line_id, partner_id, line_type,
|
||||
profile_id, context=None):
|
||||
"""Keep the same features as in standard and call super. If an account
|
||||
is returned, call the method to compute line values.
|
||||
"""
|
||||
|
||||
@@ -82,7 +82,8 @@ if not hasattr(std_pos_session, '_prepare_bank_statement'):
|
||||
cr, uid, [('type', '=', 'cash')], context=context)
|
||||
if not cashids:
|
||||
cashids = journal_proxy.search(
|
||||
cr, uid, [('journal_user', '=', True)], context=context)
|
||||
cr, uid, [('journal_user', '=', True)],
|
||||
context=context)
|
||||
jobj.write(
|
||||
cr, uid, [pos_config.id], {'journal_ids': [(6, 0, cashids)]})
|
||||
pos_config = jobj.browse(cr, uid, config_id, context=context)
|
||||
|
||||
@@ -18,5 +18,5 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import statement
|
||||
import parser
|
||||
from . import statement
|
||||
from . import parser
|
||||
|
||||
@@ -63,7 +63,8 @@ class AccountBankStatement(orm.Model):
|
||||
})
|
||||
return res
|
||||
|
||||
def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id,
|
||||
def create_move_from_st_line(self, cr, uid, st_line_id,
|
||||
company_currency_id,
|
||||
st_line_number, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
@@ -54,7 +54,7 @@ class AccountStatementCompletionRule(Model):
|
||||
string="Account to set"),
|
||||
}
|
||||
|
||||
def set_account(self, cr, uid, id, st_line, context=None):
|
||||
def set_account(self, cr, uid, account_id, st_line, context=None):
|
||||
"""
|
||||
If line name match regex, update account_id
|
||||
Then, call the generic st_line method to complete other values.
|
||||
@@ -69,7 +69,7 @@ class AccountStatementCompletionRule(Model):
|
||||
name = st_line['name']
|
||||
res = {}
|
||||
if name:
|
||||
rule = self.browse(cr, uid, id, context=context)
|
||||
rule = self.browse(cr, uid, account_id, context=context)
|
||||
if re.match(rule.regex, name):
|
||||
res['account_id'] = rule.account_id.id
|
||||
return res
|
||||
|
||||
@@ -87,12 +87,14 @@ class test_regex_account_completion(common.TransactionCase):
|
||||
"""Test the automatic completion on account
|
||||
"""
|
||||
self.prepare()
|
||||
statement_obj = self.st_obj.browse(self.cr, self.uid, self.statement_id)
|
||||
statement_obj = self.st_obj.browse(
|
||||
self.cr, self.uid, self.statement_id)
|
||||
statement_obj.button_auto_completion()
|
||||
statement_line1 = self.st_line_obj.browse(
|
||||
self.cr, self.uid, self.statement_line1_id)
|
||||
self.assertEquals(self.account_id, statement_line1.account_id.id,
|
||||
"The account should be the account of the completion")
|
||||
"The account should be the account of the completion"
|
||||
)
|
||||
statement_line2 = self.st_line_obj.browse(
|
||||
self.cr, self.uid, self.statement_line2_id)
|
||||
self.assertNotEqual(self.account_id, statement_line2.account_id.id,
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import statement
|
||||
from . import statement
|
||||
|
||||
@@ -110,7 +110,7 @@ class AccountStatementCompletionRule(Model):
|
||||
elif len(invoice_id) == 1:
|
||||
invoice = invoice_obj.browse(cr, uid, invoice_id[0],
|
||||
context=context)
|
||||
res['partner_id'] = invoice.partner_id.id
|
||||
res['partner_id'] = invoice.commercial_partner_id.id
|
||||
# we want the move to have the same ref than the found
|
||||
# invoice's move, thus it will be easier to link them for the
|
||||
# accountants
|
||||
@@ -151,7 +151,8 @@ class AccountBankStatement(Model):
|
||||
|
||||
:param browse_record st_line: account.bank.statement.line record to
|
||||
create the move from.
|
||||
:param int/long move_id: ID of the account.move to link the move line
|
||||
:param int/long move_id: ID of the account.move to link the move
|
||||
line
|
||||
:param float debit: debit amount of the move line
|
||||
:param float credit: credit amount of the move line
|
||||
:param int/long currency_id: ID of currency of the move line to
|
||||
@@ -162,7 +163,8 @@ class AccountBankStatement(Model):
|
||||
line if different from the statement line account ID
|
||||
:param int/long analytic_id: ID of analytic account to put on the
|
||||
move line
|
||||
:param int/long partner_id: ID of the partner to put on the move line
|
||||
:param int/long partner_id: ID of the partner to put on the move
|
||||
line
|
||||
:return: dict of value to create() the account.move.line
|
||||
"""
|
||||
res = super(AccountBankStatement, self)._prepare_move_line_vals(
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
statement_id: statement_transactionid_test1
|
||||
transaction_id: XXX66Z
|
||||
ref: 6
|
||||
date: '2014-01-06'
|
||||
date: !eval "'%s-01-06' %(datetime.now().year)"
|
||||
amount: 118.4
|
||||
-
|
||||
I run the auto complete
|
||||
|
||||
@@ -18,5 +18,5 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import parser
|
||||
import statement
|
||||
from . import parser
|
||||
from . import statement
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
the importation of different bank and offices that uses transactionID.
|
||||
|
||||
This module allows you to import your bank transactions with a standard .csv
|
||||
or .xls file (you'll find samples in the 'data' folder). It respects the chosen
|
||||
profile (model provided by the account_statement_ext module) to generate the
|
||||
entries.
|
||||
or .xls file (you'll find samples in the 'data' folder). It respects the
|
||||
chosen profile (model provided by the account_statement_ext module) to
|
||||
generate the entries.
|
||||
|
||||
This module can handle a commission taken by the payment office and has the
|
||||
following format:
|
||||
@@ -48,8 +48,8 @@
|
||||
* amount: amount paid in the currency of the journal used in the importation
|
||||
profile
|
||||
* commission_amount: amount of the comission for each line
|
||||
* label: the comunication given by the payment office, used as communication in
|
||||
the generated entries.
|
||||
* label: the comunication given by the payment office, used as communication
|
||||
in the generated entries.
|
||||
""",
|
||||
'website': 'http://www.camptocamp.com',
|
||||
'installable': False,
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import transactionid_file_parser
|
||||
from . import transactionid_file_parser
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
#
|
||||
##############################################################################
|
||||
import datetime
|
||||
from account_statement_base_import.parser.file_parser import FileParser
|
||||
from openerp.tools import ustr
|
||||
from account_statement_base_import.parser.file_parser import (
|
||||
FileParser, float_or_zero
|
||||
)
|
||||
|
||||
|
||||
class TransactionIDFileParser(FileParser):
|
||||
@@ -36,14 +39,15 @@ class TransactionIDFileParser(FileParser):
|
||||
:param list: header : specify header fields if the csv file has no
|
||||
header
|
||||
"""
|
||||
extra_fields = {'transaction_id': unicode}
|
||||
conversion_dict = {
|
||||
'transaction_id': ustr,
|
||||
'label': ustr,
|
||||
'date': datetime.datetime,
|
||||
'amount': float_or_zero,
|
||||
}
|
||||
super(TransactionIDFileParser, self).__init__(
|
||||
profile, extra_fields=extra_fields, ftype=ftype, header=header,
|
||||
profile, extra_fields=conversion_dict, ftype=ftype, header=header,
|
||||
**kwargs)
|
||||
# ref is replaced by transaction_id thus we delete it from check
|
||||
self.keys_to_validate = [
|
||||
k for k in self.keys_to_validate if k != 'ref']
|
||||
del self.conversion_dict['ref']
|
||||
|
||||
@classmethod
|
||||
def parser_for(cls, parser_name):
|
||||
@@ -54,9 +58,9 @@ class TransactionIDFileParser(FileParser):
|
||||
|
||||
def get_st_line_vals(self, line, *args, **kwargs):
|
||||
"""This method must return a dict of vals that can be passed to create
|
||||
method of statement line in order to record it. It is the responsibility
|
||||
of every parser to give this dict of vals, so each one can implement his
|
||||
own way of recording the lines.
|
||||
method of statement line in order to record it. It is the
|
||||
responsibility of every parser to give this dict of vals, so each one
|
||||
can implement his own way of recording the lines.
|
||||
:param: line: a dict of vals that represent a line of
|
||||
result_row_list
|
||||
:return: dict of values to give to the create method of statement
|
||||
|
||||
@@ -39,10 +39,10 @@ origin, free reference) and above all, to understand which field will be
|
||||
copied in the reference field of the move and move lines.
|
||||
|
||||
The approach here is to state simple rules with one concern: consistency.
|
||||
The reference of the move lines must be the number of the document at
|
||||
their very origin (number of a sales order, of an external document
|
||||
like a supplier invoice, ...). The goal is for the accountant to be
|
||||
able to trace to the source document from a ledger).
|
||||
The reference of the move lines must be the number of the document at their
|
||||
very origin (number of a sales order, of an external document like a supplier
|
||||
invoice, ...). The goal is for the accountant to be able to trace to the
|
||||
source document from a ledger).
|
||||
The description of a line should always be... well, a description. Not a number
|
||||
or a cryptic reference.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user