This commit is contained in:
Pedro M. Baeza
2014-08-04 15:29:05 +02:00
parent 2c1773e7be
commit 44a59ce588
60 changed files with 615 additions and 458 deletions

View File

@@ -82,4 +82,4 @@ many offices.
'auto_install': False, 'auto_install': False,
'license': 'AGPL-3', 'license': 'AGPL-3',
'application': True, 'application': True,
} }

View File

@@ -36,5 +36,5 @@ Reconcile rules with transaction_ref
'auto_install': False, 'auto_install': False,
'installable': True, 'installable': True,
'images': [] 'images': []
} }
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@@ -36,4 +36,3 @@ class account_easy_reconcile_method(orm.Model):
'Advanced. Partner and Transaction Ref. vs Ref.'), 'Advanced. Partner and Transaction Ref. vs Ref.'),
] ]
return methods return methods

View File

@@ -24,6 +24,7 @@ from operator import itemgetter, attrgetter
class easy_reconcile_base(orm.AbstractModel): class easy_reconcile_base(orm.AbstractModel):
"""Abstract Model for reconciliation methods""" """Abstract Model for reconciliation methods"""
_name = 'easy.reconcile.base' _name = 'easy.reconcile.base'

View File

@@ -26,6 +26,7 @@ from openerp.tools.translate import _
class easy_reconcile_options(orm.AbstractModel): class easy_reconcile_options(orm.AbstractModel):
"""Options of a reconciliation profile """Options of a reconciliation profile
Columns shared by the configuration of methods Columns shared by the configuration of methods
@@ -81,7 +82,8 @@ class account_easy_reconcile_method(orm.Model):
return [ return [
('easy.reconcile.simple.name', 'Simple. Amount and Name'), ('easy.reconcile.simple.name', 'Simple. Amount and Name'),
('easy.reconcile.simple.partner', 'Simple. Amount and Partner'), ('easy.reconcile.simple.partner', 'Simple. Amount and Partner'),
('easy.reconcile.simple.reference', 'Simple. Amount and Reference'), ('easy.reconcile.simple.reference',
'Simple. Amount and Reference'),
] ]
def _get_rec_method(self, cr, uid, context=None): def _get_rec_method(self, cr, uid, context=None):
@@ -100,7 +102,7 @@ class account_easy_reconcile_method(orm.Model):
string='Task', string='Task',
required=True, required=True,
ondelete='cascade'), ondelete='cascade'),
'company_id': fields.related('task_id','company_id', 'company_id': fields.related('task_id', 'company_id',
relation='res.company', relation='res.company',
type='many2one', type='many2one',
string='Company', string='Company',
@@ -281,7 +283,7 @@ class account_easy_reconcile(orm.Model):
""" Open the view of move line with the unreconciled move lines """ Open the view of move line with the unreconciled move lines
""" """
assert len(ids) == 1 , \ assert len(ids) == 1, \
"You can only open entries from one profile at a time" "You can only open entries from one profile at a time"
obj_move_line = self.pool.get('account.move.line') obj_move_line = self.pool.get('account.move.line')
@@ -301,7 +303,7 @@ class account_easy_reconcile(orm.Model):
""" Open the view of move line with the unreconciled move lines """ Open the view of move line with the unreconciled move lines
""" """
assert len(ids) == 1 , \ assert len(ids) == 1, \
"You can only open entries from one profile at a time" "You can only open entries from one profile at a time"
obj_move_line = self.pool.get('account.move.line') obj_move_line = self.pool.get('account.move.line')

View File

@@ -24,6 +24,7 @@ from openerp.tools.translate import _
class easy_reconcile_history(orm.Model): class easy_reconcile_history(orm.Model):
""" Store an history of the runs per profile """ Store an history of the runs per profile
Each history stores the list of reconciliations done""" Each history stores the list of reconciliations done"""
@@ -81,7 +82,7 @@ class easy_reconcile_history(orm.Model):
relation='account.move.line', relation='account.move.line',
readonly=True, readonly=True,
multi='lines'), multi='lines'),
'company_id': fields.related('easy_reconcile_id','company_id', 'company_id': fields.related('easy_reconcile_id', 'company_id',
relation='res.company', relation='res.company',
type='many2one', type='many2one',
string='Company', string='Company',

View File

@@ -41,7 +41,7 @@ class easy_reconcile_simple(AbstractModel):
count = 0 count = 0
res = [] res = []
while (count < len(lines)): while (count < len(lines)):
for i in xrange(count+1, len(lines)): for i in xrange(count + 1, len(lines)):
writeoff_account_id = False writeoff_account_id = False
if lines[count][self._key_field] != lines[i][self._key_field]: if lines[count][self._key_field] != lines[i][self._key_field]:
break break

View File

@@ -19,14 +19,14 @@
# #
############################################################################## ##############################################################################
{'name' : 'Invoices Reference', {'name': 'Invoices Reference',
'version' : '1.0', 'version': '1.0',
'author' : 'Camptocamp', 'author': 'Camptocamp',
'maintainer': 'Camptocamp', 'maintainer': 'Camptocamp',
'license': 'AGPL-3', 'license': 'AGPL-3',
'category': 'category', 'category': 'category',
'complexity': "easy", 'complexity': "easy",
'depends' : ['account', 'depends': ['account',
], ],
'description': """ 'description': """
Invoices Reference Invoices Reference
@@ -143,4 +143,4 @@ Information propagated to the move lines:
], ],
'installable': True, 'installable': True,
'auto_install': False, 'auto_install': False,
} }

View File

@@ -33,7 +33,8 @@ class account_move(orm.Model):
if invoice: if invoice:
assert isinstance(invoice, orm.browse_record) assert isinstance(invoice, orm.browse_record)
invoice_obj = self.pool['account.invoice'] invoice_obj = self.pool['account.invoice']
ref = invoice_obj._ref_from_invoice(cr, uid, invoice, context=context) ref = invoice_obj._ref_from_invoice(
cr, uid, invoice, context=context)
vals = vals.copy() vals = vals.copy()
vals['ref'] = ref vals['ref'] = ref
move_id = super(account_move, self).\ move_id = super(account_move, self).\

View File

@@ -40,4 +40,4 @@ Needs `statement_voucher_killer`
'test': [], 'test': [],
'installable': True, 'installable': True,
'auto_install': True, 'auto_install': True,
} }

View File

@@ -27,6 +27,7 @@ from openerp.addons.account_statement_base_completion.statement import ErrorTooM
class AccountStatementCompletionRule(Model): class AccountStatementCompletionRule(Model):
"""Add a rule based on transaction ID""" """Add a rule based on transaction ID"""
_inherit = "account.statement.completion.rule" _inherit = "account.statement.completion.rule"
@@ -64,15 +65,20 @@ class AccountStatementCompletionRule(Model):
raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched by more than ' 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)) 'one partner for account number "%s".') % (st_line['name'], st_line['ref'], partner_acc_number))
if len(ids) == 1: 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 res['partner_id'] = partner.id
st_vals = st_obj.get_values_for_line(cr, st_vals = st_obj.get_values_for_line(cr,
uid, uid,
profile_id=st_line['profile_id'], profile_id=st_line[
master_account_id=st_line['master_account_id'], 'profile_id'],
partner_id=res.get('partner_id', False), master_account_id=st_line[
'master_account_id'],
partner_id=res.get(
'partner_id', False),
line_type=st_line['type'], line_type=st_line['type'],
amount=st_line['amount'] if st_line['amount'] else 0.0, amount=st_line['amount'] if st_line[
'amount'] else 0.0,
context=context) context=context)
res.update(st_vals) res.update(st_vals)
return res return res

View File

@@ -30,14 +30,20 @@ class bankaccount_completion(common.TransactionCase):
def prepare(self): def prepare(self):
self.company_a = self.browse_ref('base.main_company') self.company_a = self.browse_ref('base.main_company')
self.profile_obj = self.registry("account.statement.profile") self.profile_obj = self.registry("account.statement.profile")
self.account_bank_statement_obj = self.registry("account.bank.statement") self.account_bank_statement_obj = self.registry(
self.account_bank_statement_line_obj = self.registry("account.bank.statement.line") "account.bank.statement")
self.completion_rule_id = self.ref('account_statement_bankaccount_completion.bank_statement_completion_rule_10') self.account_bank_statement_line_obj = self.registry(
self.journal_id = self.registry("ir.model.data").get_object_reference(self.cr, self. uid, "account", "bank_journal")[1] "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.partner_id = self.ref('base.main_partner') self.partner_id = self.ref('base.main_partner')
# Create the profile # Create the profile
self.account_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "account", "a_recv")[1] self.account_id = self.registry("ir.model.data").get_object_reference(
self.journal_id = self.registry("ir.model.data").get_object_reference(self.cr, self. uid, "account", "bank_journal")[1] 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, { self.profile_id = self.profile_obj.create(self.cr, self.uid, {
"name": "TEST", "name": "TEST",
"commission_account_id": self.account_id, "commission_account_id": self.account_id,
@@ -82,10 +88,15 @@ class bankaccount_completion(common.TransactionCase):
statement line statement line
""" """
self.prepare() self.prepare()
statement_line = self.account_bank_statement_line_obj.browse(self.cr, self.uid, self.statement_line_id) statement_line = self.account_bank_statement_line_obj.browse(
self.cr, self.uid, self.statement_line_id)
# before import, the # before import, the
self.assertFalse(statement_line.partner_id, "Partner_id must be blank before completion") self.assertFalse(
statement_obj = self.account_bank_statement_obj.browse(self.cr, self.uid, self.statement_id) statement_line.partner_id, "Partner_id must be blank before completion")
statement_obj = self.account_bank_statement_obj.browse(
self.cr, self.uid, self.statement_id)
statement_obj.button_auto_completion() statement_obj.button_auto_completion()
statement_line = self.account_bank_statement_line_obj.browse(self.cr, self.uid, self.statement_line_id) statement_line = self.account_bank_statement_line_obj.browse(
self.assertEquals(self.partner_id, statement_line.partner_id['id'], "Missing expected partner id after completion") self.cr, self.uid, self.statement_line_id)
self.assertEquals(self.partner_id, statement_line.partner_id[
'id'], "Missing expected partner id after completion")

View File

@@ -74,4 +74,4 @@
'images': [], 'images': [],
'auto_install': False, 'auto_install': False,
'license': 'AGPL-3', 'license': 'AGPL-3',
} }

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################# ##########################################################################
# # # #
# Copyright (C) 2011 Akretion & Camptocamp # Copyright (C) 2011 Akretion & Camptocamp
# Author : Sébastien BEAU, Joel Grand-Guillaume # # Author : Sébastien BEAU, Joel Grand-Guillaume #
@@ -17,13 +17,14 @@
# You should have received a copy of the GNU Affero General Public License # # 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/>. # # along with this program. If not, see <http://www.gnu.org/licenses/>. #
# # # #
################################################################################# ##########################################################################
from openerp.osv.orm import Model from openerp.osv.orm import Model
from openerp.osv import fields from openerp.osv import fields
class res_partner(Model): class res_partner(Model):
""" """
Add a bank label on the partner so that we can use it to match Add a bank label on the partner so that we can use it to match
this partner when we found this in a statement line. this partner when we found this in a statement line.

View File

@@ -40,10 +40,12 @@ _logger = logging.getLogger(__name__)
class ErrorTooManyPartner(Exception): class ErrorTooManyPartner(Exception):
""" """
New Exception definition that is raised when more than one partner is matched by New Exception definition that is raised when more than one partner is matched by
the completion rule. the completion rule.
""" """
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
@@ -55,6 +57,7 @@ class ErrorTooManyPartner(Exception):
class AccountStatementProfil(orm.Model): class AccountStatementProfil(orm.Model):
""" """
Extend the class to add rules per profile that will match at least the partner, Extend the class to add rules per profile that will match at least the partner,
but it could also be used to match other values as well. but it could also be used to match other values as well.
@@ -100,7 +103,8 @@ class AccountStatementProfil(orm.Model):
if context is None: if context is None:
context = {} context = {}
if not calls: if not calls:
calls = self._get_rules(cr, uid, line['profile_id'], context=context) calls = self._get_rules(
cr, uid, line['profile_id'], context=context)
rule_obj = self.pool.get('account.statement.completion.rule') rule_obj = self.pool.get('account.statement.completion.rule')
for call in calls: for call in calls:
@@ -116,6 +120,7 @@ class AccountStatementProfil(orm.Model):
class AccountStatementCompletionRule(orm.Model): class AccountStatementCompletionRule(orm.Model):
""" """
This will represent all the completion method that we can have to This will represent all the completion method that we can have to
fullfill the bank statement lines. You'll be able to extend them in you own module fullfill the bank statement lines. You'll be able to extend them in you own module
@@ -134,9 +139,12 @@ class AccountStatementCompletionRule(orm.Model):
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 [ return [
('get_from_ref_and_invoice', 'From line reference (based on customer invoice number)'), ('get_from_ref_and_invoice',
('get_from_ref_and_supplier_invoice', 'From line reference (based on supplier invoice number)'), 'From line reference (based on customer invoice number)'),
('get_from_label_and_partner_field', 'From line label (based on partner field)'), ('get_from_ref_and_supplier_invoice',
'From line reference (based on supplier invoice number)'),
('get_from_label_and_partner_field',
'From line label (based on partner field)'),
('get_from_label_and_partner_name', 'From line label (based on partner name)')] ('get_from_label_and_partner_name', 'From line label (based on partner name)')]
def __get_functions(self, cr, uid, context=None): def __get_functions(self, cr, uid, context=None):
@@ -272,7 +280,8 @@ class AccountStatementCompletionRule(orm.Model):
[('bank_statement_label', '!=', False)]) [('bank_statement_label', '!=', False)])
line_ids = context.get('line_ids', []) line_ids = context.get('line_ids', [])
for partner in partner_obj.browse(cr, uid, partner_ids, context=context): for partner in partner_obj.browse(cr, uid, partner_ids, context=context):
vals = '|'.join(re.escape(x.strip()) for x in partner.bank_statement_label.split(';')) vals = '|'.join(re.escape(x.strip())
for x in partner.bank_statement_label.split(';'))
or_regex = ".*%s.*" % vals or_regex = ".*%s.*" % vals
sql = ("SELECT id from account_bank_statement_line" sql = ("SELECT id from account_bank_statement_line"
" WHERE id in %s" " WHERE id in %s"
@@ -292,11 +301,15 @@ class AccountStatementCompletionRule(orm.Model):
res['partner_id'] = found_partner[0].id res['partner_id'] = found_partner[0].id
st_vals = st_obj.get_values_for_line(cr, st_vals = st_obj.get_values_for_line(cr,
uid, uid,
profile_id=st_line['profile_id'], profile_id=st_line[
master_account_id=st_line['master_account_id'], 'profile_id'],
partner_id=found_partner[0].id, master_account_id=st_line[
'master_account_id'],
partner_id=found_partner[
0].id,
line_type=False, line_type=False,
amount=st_line['amount'] if st_line['amount'] else 0.0, amount=st_line['amount'] if st_line[
'amount'] else 0.0,
context=context) context=context)
res.update(st_vals) res.update(st_vals)
return res return res
@@ -320,7 +333,8 @@ class AccountStatementCompletionRule(orm.Model):
res = {} res = {}
# We memoize allowed partner # We memoize allowed partner
if not context.get('partner_memoizer'): if not context.get('partner_memoizer'):
context['partner_memoizer'] = tuple(self.pool['res.partner'].search(cr, uid, [])) context['partner_memoizer'] = tuple(
self.pool['res.partner'].search(cr, uid, []))
if not context['partner_memoizer']: if not context['partner_memoizer']:
return res return res
st_obj = self.pool.get('account.bank.statement.line') st_obj = self.pool.get('account.bank.statement.line')
@@ -335,7 +349,8 @@ class AccountStatementCompletionRule(orm.Model):
SELECT id, regexp_matches(%s, regexp_replace(name,'([\.\^\$\*\+\?\(\)\[\{\\\|])', %s, 'g'), 'i') AS name_match FROM res_partner SELECT id, regexp_matches(%s, regexp_replace(name,'([\.\^\$\*\+\?\(\)\[\{\\\|])', %s, 'g'), 'i') AS name_match FROM res_partner
WHERE id IN %s) AS res_patner_matcher WHERE id IN %s) AS res_patner_matcher
WHERE name_match IS NOT NULL""" WHERE name_match IS NOT NULL"""
cr.execute(sql, (st_line['name'], r"\\\1", context['partner_memoizer'])) cr.execute(
sql, (st_line['name'], r"\\\1", context['partner_memoizer']))
result = cr.fetchall() result = cr.fetchall()
if not result: if not result:
return res return res
@@ -347,14 +362,17 @@ class AccountStatementCompletionRule(orm.Model):
st_vals = st_obj.get_values_for_line(cr, st_vals = st_obj.get_values_for_line(cr,
uid, uid,
profile_id=st_line['profile_id'], profile_id=st_line['profile_id'],
master_account_id=st_line['master_account_id'], master_account_id=st_line[
'master_account_id'],
partner_id=res['partner_id'], partner_id=res['partner_id'],
line_type=False, line_type=False,
amount=st_line['amount'] if st_line['amount'] else 0.0, amount=st_line['amount'] if st_line[
'amount'] else 0.0,
context=context) context=context)
res.update(st_vals) res.update(st_vals)
return res return res
class AccountStatement(orm.Model): class AccountStatement(orm.Model):
_inherit = "account.bank.statement" _inherit = "account.bank.statement"
@@ -369,12 +387,13 @@ class AccountStatement(orm.Model):
stat = self.browse(cr, uid, stat_id, context=context) stat = self.browse(cr, uid, stat_id, context=context)
raise orm.except_orm(_('User error'), raise orm.except_orm(_('User error'),
_('You should fill all account on the line of the' _('You should fill all account on the line of the'
' statement %s')%stat.name) ' statement %s') % stat.name)
return super(AccountStatement, self).button_confirm_bank( return super(AccountStatement, self).button_confirm_bank(
cr, uid, ids, context=context) cr, uid, ids, context=context)
class AccountStatementLine(orm.Model): class AccountStatementLine(orm.Model):
""" """
Add sparse field on the statement line to allow to store all 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 bank infos that are given by a bank/office. You can then add you own in your
@@ -424,7 +443,8 @@ class AccountStatementLine(orm.Model):
if line.get('already_completed'): if line.get('already_completed'):
return {} return {}
# Ask the rule # Ask the rule
vals = profile_obj._find_values_from_rules(cr, uid, rules, line, context) vals = profile_obj._find_values_from_rules(
cr, uid, rules, line, context)
if vals: if vals:
vals['id'] = line['id'] vals['id'] = line['id']
return vals return vals
@@ -434,7 +454,8 @@ class AccountStatementLine(orm.Model):
"""Return writeable by SQL columns""" """Return writeable by SQL columns"""
statement_line_obj = self.pool['account.bank.statement.line'] statement_line_obj = self.pool['account.bank.statement.line']
model_cols = statement_line_obj._columns model_cols = statement_line_obj._columns
avail = [k for k, col in model_cols.iteritems() if not hasattr(col, '_fnct')] avail = [
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] keys = [k for k in statement_store[0].keys() if k in avail]
# add sparse fields.. # add sparse fields..
if include_serializable: if include_serializable:
@@ -472,7 +493,8 @@ class AccountStatementLine(orm.Model):
""" """
statement_line_obj = self.pool['account.bank.statement.line'] statement_line_obj = self.pool['account.bank.statement.line']
model_cols = statement_line_obj._columns model_cols = statement_line_obj._columns
sparse_fields = dict([(k, col) for k, col in model_cols.iteritems() if isinstance(col, fields.sparse) and col._type == 'char']) sparse_fields = dict([(k, col) for k, col in model_cols.iteritems() if isinstance(
col, fields.sparse) and col._type == 'char'])
values = [] values = []
for statement in statement_store: for statement in statement_store:
to_json_k = set() to_json_k = set()
@@ -480,7 +502,8 @@ class AccountStatementLine(orm.Model):
for k, col in sparse_fields.iteritems(): for k, col in sparse_fields.iteritems():
if k in st_copy: if k in st_copy:
to_json_k.add(col.serialization_field) to_json_k.add(col.serialization_field)
serialized = st_copy.setdefault(col.serialization_field, {}) serialized = st_copy.setdefault(
col.serialization_field, {})
serialized[k] = st_copy[k] serialized[k] = st_copy[k]
for k in to_json_k: for k in to_json_k:
st_copy[k] = simplejson.dumps(st_copy[k]) st_copy[k] = simplejson.dumps(st_copy[k])
@@ -493,13 +516,16 @@ class AccountStatementLine(orm.Model):
does not exist""" does not exist"""
statement_line_obj = self.pool['account.bank.statement.line'] statement_line_obj = self.pool['account.bank.statement.line']
statement_line_obj.check_access_rule(cr, uid, [], 'create') statement_line_obj.check_access_rule(cr, uid, [], 'create')
statement_line_obj.check_access_rights(cr, uid, 'create', raise_exception=True) statement_line_obj.check_access_rights(
cols = self._get_available_columns(statement_store, include_serializable=True) cr, uid, 'create', raise_exception=True)
cols = self._get_available_columns(
statement_store, include_serializable=True)
statement_store = self._prepare_manyinsert(statement_store, cols) statement_store = self._prepare_manyinsert(statement_store, cols)
tmp_vals = (', '.join(cols), ', '.join(['%%(%s)s' % i for i in cols])) tmp_vals = (', '.join(cols), ', '.join(['%%(%s)s' % i for i in cols]))
sql = "INSERT INTO account_bank_statement_line (%s) VALUES (%s);" % tmp_vals sql = "INSERT INTO account_bank_statement_line (%s) VALUES (%s);" % tmp_vals
try: try:
cr.executemany(sql, tuple(self._serialize_sparse_fields(cols, statement_store))) cr.executemany(
sql, tuple(self._serialize_sparse_fields(cols, statement_store)))
except psycopg2.Error as sql_err: except psycopg2.Error as sql_err:
cr.rollback() cr.rollback()
raise osv.except_osv(_("ORM bypass error"), raise osv.except_osv(_("ORM bypass error"),
@@ -526,6 +552,7 @@ class AccountStatementLine(orm.Model):
class AccountBankStatement(orm.Model): class AccountBankStatement(orm.Model):
""" """
We add a basic button and stuff to support the auto-completion We add a basic button and stuff to support the auto-completion
of the bank statement once line have been imported or manually fullfill. of the bank statement once line have been imported or manually fullfill.
@@ -556,11 +583,13 @@ class AccountBankStatement(orm.Model):
context=context)['completion_logs'] context=context)['completion_logs']
log = log if log else "" log = log if log else ""
completion_date = datetime.datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT) completion_date = datetime.datetime.now().strftime(
DEFAULT_SERVER_DATETIME_FORMAT)
message = (_("%s Bank Statement ID %s has %s/%s lines completed by %s \n%s\n%s\n") % message = (_("%s Bank Statement ID %s has %s/%s lines completed by %s \n%s\n%s\n") %
(completion_date, stat_id, number_imported, number_line, user_name, (completion_date, stat_id, number_imported, number_line, user_name,
error_msg, log)) error_msg, log))
self.write(cr, uid, [stat_id], {'completion_logs': message}, context=context) self.write(
cr, uid, [stat_id], {'completion_logs': message}, context=context)
body = (_('Statement ID %s auto-completed for %s/%s lines completed') % body = (_('Statement ID %s auto-completed for %s/%s lines completed') %
(stat_id, number_imported, number_line)), (stat_id, number_imported, number_line)),
@@ -581,14 +610,16 @@ class AccountBankStatement(orm.Model):
profile_obj = self.pool.get('account.statement.profile') profile_obj = self.pool.get('account.statement.profile')
compl_lines = 0 compl_lines = 0
stat_line_obj.check_access_rule(cr, uid, [], 'create') stat_line_obj.check_access_rule(cr, uid, [], 'create')
stat_line_obj.check_access_rights(cr, uid, 'create', raise_exception=True) stat_line_obj.check_access_rights(
cr, uid, 'create', raise_exception=True)
for stat in self.browse(cr, uid, ids, context=context): for stat in self.browse(cr, uid, ids, context=context):
msg_lines = [] msg_lines = []
ctx = context.copy() ctx = context.copy()
ctx['line_ids'] = tuple((x.id for x in stat.line_ids)) ctx['line_ids'] = tuple((x.id for x in stat.line_ids))
b_profile = stat.profile_id b_profile = stat.profile_id
rules = profile_obj._get_rules(cr, uid, b_profile, context=context) rules = profile_obj._get_rules(cr, uid, b_profile, context=context)
profile_id = b_profile.id # Only for perfo even it gains almost nothing # Only for perfo even it gains almost nothing
profile_id = b_profile.id
master_account_id = b_profile.receivable_account_id master_account_id = b_profile.receivable_account_id
master_account_id = master_account_id.id if master_account_id else False master_account_id = master_account_id.id if master_account_id else False
res = False res = False
@@ -606,17 +637,20 @@ class AccountBankStatement(orm.Model):
except Exception, exc: except Exception, exc:
msg_lines.append(repr(exc)) msg_lines.append(repr(exc))
error_type, error_value, trbk = sys.exc_info() error_type, error_value, trbk = sys.exc_info()
st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value) st = "Error: %s\nDescription: %s\nTraceback:" % (
error_type.__name__, error_value)
st += ''.join(traceback.format_tb(trbk, 30)) st += ''.join(traceback.format_tb(trbk, 30))
_logger.error(st) _logger.error(st)
if res: 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: try:
stat_line_obj._update_line(cr, uid, res, context=context) stat_line_obj._update_line(
cr, uid, res, context=context)
except Exception as exc: except Exception as exc:
msg_lines.append(repr(exc)) msg_lines.append(repr(exc))
error_type, error_value, trbk = sys.exc_info() error_type, error_value, trbk = sys.exc_info()
st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value) st = "Error: %s\nDescription: %s\nTraceback:" % (
error_type.__name__, error_value)
st += ''.join(traceback.format_tb(trbk, 30)) st += ''.join(traceback.format_tb(trbk, 30))
_logger.error(st) _logger.error(st)
# we can commit as it is not needed to be atomic # we can commit as it is not needed to be atomic

View File

@@ -23,7 +23,8 @@ from openerp.tests import common
import time import time
from collections import namedtuple from collections import namedtuple
name_completion_case = namedtuple("name_completion_case", ["partner_name", "line_label", "should_match"]) name_completion_case = namedtuple(
"name_completion_case", ["partner_name", "line_label", "should_match"])
NAMES_COMPLETION_CASES = [ NAMES_COMPLETION_CASES = [
name_completion_case("Acsone", "Line for Acsone SA", True), name_completion_case("Acsone", "Line for Acsone SA", True),
name_completion_case("Acsone", "Line for Acsone", True), name_completion_case("Acsone", "Line for Acsone", True),
@@ -34,11 +35,14 @@ NAMES_COMPLETION_CASES = [
name_completion_case("é@|r{}", "Acsone é@|r{} for line", True), name_completion_case("é@|r{}", "Acsone é@|r{} for line", True),
name_completion_case("Acsone", "A..one for line", False), name_completion_case("Acsone", "A..one for line", False),
name_completion_case("A.one SA", "A.one SA for line", True), name_completion_case("A.one SA", "A.one SA for line", True),
name_completion_case("Acsone SA", "Line for Acsone ([^a-zA-Z0-9 -]) SA test", False), name_completion_case(
name_completion_case("Acsone ([^a-zA-Z0-9 -]) SA", "Line for Acsone ([^a-zA-Z0-9 -]) SA test", True), "Acsone SA", "Line for Acsone ([^a-zA-Z0-9 -]) SA test", False),
name_completion_case(r"Acsone (.^$*+?()[{\| -]\) SA", r"Line for Acsone (.^$*+?()[{\| -]\) SA test", True), name_completion_case(
"Acsone ([^a-zA-Z0-9 -]) SA", "Line for Acsone ([^a-zA-Z0-9 -]) SA test", True),
name_completion_case(
r"Acsone (.^$*+?()[{\| -]\) SA", r"Line for Acsone (.^$*+?()[{\| -]\) SA test", True),
name_completion_case("Acšone SA", "Line for Acšone SA test", True), name_completion_case("Acšone SA", "Line for Acšone SA test", True),
] ]
class base_completion(common.TransactionCase): class base_completion(common.TransactionCase):
@@ -48,8 +52,10 @@ class base_completion(common.TransactionCase):
self.company_a = self.browse_ref('base.main_company') self.company_a = self.browse_ref('base.main_company')
self.profile_obj = self.registry("account.statement.profile") self.profile_obj = self.registry("account.statement.profile")
self.partner_obj = self.registry("res.partner") self.partner_obj = self.registry("res.partner")
self.account_bank_statement_obj = self.registry("account.bank.statement") self.account_bank_statement_obj = self.registry(
self.account_bank_statement_line_obj = self.registry("account.bank.statement.line") "account.bank.statement")
self.account_bank_statement_line_obj = self.registry(
"account.bank.statement.line")
self.journal_id = self.ref("account.bank_journal") self.journal_id = self.ref("account.bank_journal")
self.partner_id = self.ref('base.main_partner') self.partner_id = self.ref('base.main_partner')
self.account_id = self.ref("account.a_recv") self.account_id = self.ref("account.a_recv")
@@ -60,7 +66,8 @@ class base_completion(common.TransactionCase):
Test the automatic completion of the partner_id based if the name of the partner appears in Test the automatic completion of the partner_id based if the name of the partner appears in
the statement line label the statement line label
""" """
self.completion_rule_id = self.ref('account_statement_base_completion.bank_statement_completion_rule_3') self.completion_rule_id = self.ref(
'account_statement_base_completion.bank_statement_completion_rule_3')
# Create the profile # Create the profile
self.profile_id = self.profile_obj.create(self.cr, self.uid, { self.profile_id = self.profile_obj.create(self.cr, self.uid, {
"name": "TEST", "name": "TEST",
@@ -77,18 +84,23 @@ class base_completion(common.TransactionCase):
}) })
for case in NAMES_COMPLETION_CASES: for case in NAMES_COMPLETION_CASES:
self.partner_obj.write(self.cr, self.uid, self.partner_id, {'name': case.partner_name}) self.partner_obj.write(
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, { statement_line_id = self.account_bank_statement_line_obj.create(self.cr, self.uid, {
'amount': 1000.0, 'amount': 1000.0,
'name': case.line_label, 'name': case.line_label,
'ref': 'My ref', 'ref': 'My ref',
'statement_id': self.statement_id, 'statement_id': self.statement_id,
}) })
statement_line = self.account_bank_statement_line_obj.browse(self.cr, self.uid, statement_line_id) statement_line = self.account_bank_statement_line_obj.browse(
self.assertFalse(statement_line.partner_id, "Partner_id must be blank before completion") self.cr, self.uid, statement_line_id)
statement_obj = self.account_bank_statement_obj.browse(self.cr, self.uid, self.statement_id) self.assertFalse(
statement_line.partner_id, "Partner_id must be blank before completion")
statement_obj = self.account_bank_statement_obj.browse(
self.cr, self.uid, self.statement_id)
statement_obj.button_auto_completion() statement_obj.button_auto_completion()
statement_line = self.account_bank_statement_line_obj.browse(self.cr, self.uid, statement_line_id) statement_line = self.account_bank_statement_line_obj.browse(
self.cr, self.uid, statement_line_id)
if case.should_match: if case.should_match:
self.assertEquals(self.partner_id, statement_line.partner_id['id'], self.assertEquals(self.partner_id, statement_line.partner_id['id'],
"Missing expected partner id after completion (partner_name: %s, line_name: %s)" % (case.partner_name, case.line_label)) "Missing expected partner id after completion (partner_name: %s, line_name: %s)" % (case.partner_name, case.line_label))

View File

@@ -66,4 +66,4 @@
'images': [], 'images': [],
'auto_install': False, 'auto_install': False,
'license': 'AGPL-3', 'license': 'AGPL-3',
} }

View File

@@ -28,12 +28,15 @@ try:
except: except:
raise Exception(_('Please install python lib xlrd')) raise Exception(_('Please install python lib xlrd'))
def float_or_zero(val): def float_or_zero(val):
""" Conversion function used to manage """ Conversion function used to manage
empty string into float usecase""" empty string into float usecase"""
return float(val) if val else 0.0 return float(val) if val else 0.0
class FileParser(BankStatementImportParser): class FileParser(BankStatementImportParser):
""" """
Generic abstract class for defining parser for .csv, .xls or .xlsx file format. Generic abstract class for defining parser for .csv, .xls or .xlsx file format.
""" """
@@ -48,7 +51,7 @@ class FileParser(BankStatementImportParser):
""" """
super(FileParser, self).__init__(parse_name, **kwargs) super(FileParser, self).__init__(parse_name, **kwargs)
if ftype in ('csv', 'xls' ,'xlsx'): if ftype in ('csv', 'xls', 'xlsx'):
self.ftype = ftype[0:3] self.ftype = ftype[0:3]
else: else:
raise except_osv(_('User Error'), raise except_osv(_('User Error'),
@@ -161,8 +164,10 @@ class FileParser(BankStatementImportParser):
" value: %s \n \n" " value: %s \n \n"
" \n Please check the line with ref: %s" " \n Please check the line with ref: %s"
" \n \n Detail: %s") % (rule, " \n \n Detail: %s") % (rule,
line.get(rule, _('Missing')), line.get(
line.get('ref', line), rule, _('Missing')),
line.get(
'ref', line),
repr(err))) repr(err)))
else: else:
try: try:
@@ -173,7 +178,8 @@ class FileParser(BankStatementImportParser):
"\n Please check the line with ref %s:" "\n Please check the line with ref %s:"
"\n \n Detail: %s") % (line.get(rule, _('Missing')), "\n \n Detail: %s") % (line.get(rule, _('Missing')),
rule, rule,
line.get('ref', line), line.get(
'ref', line),
repr(err))) repr(err)))
return result_set return result_set
@@ -186,7 +192,8 @@ class FileParser(BankStatementImportParser):
for rule in conversion_rules: for rule in conversion_rules:
if conversion_rules[rule] == datetime.datetime: if conversion_rules[rule] == datetime.datetime:
try: try:
t_tuple = xlrd.xldate_as_tuple(line[rule], self._datemode) t_tuple = xlrd.xldate_as_tuple(
line[rule], self._datemode)
line[rule] = datetime.datetime(*t_tuple) line[rule] = datetime.datetime(*t_tuple)
except Exception as err: except Exception as err:
raise except_osv(_("Date format is not valid"), raise except_osv(_("Date format is not valid"),
@@ -195,8 +202,10 @@ class FileParser(BankStatementImportParser):
" value: %s" " value: %s"
"\n Please check the line with ref: %s" "\n Please check the line with ref: %s"
"\n \n Detail: %s") % (rule, "\n \n Detail: %s") % (rule,
line.get(rule, _('Missing')), line.get(
line.get('ref', line), rule, _('Missing')),
line.get(
'ref', line),
repr(err))) repr(err)))
else: else:
try: try:
@@ -207,7 +216,8 @@ class FileParser(BankStatementImportParser):
"\n Please check the line with ref %s:" "\n Please check the line with ref %s:"
"\n \n Detail: %s") % (line.get(rule, _('Missing')), "\n \n Detail: %s") % (line.get(rule, _('Missing')),
rule, rule,
line.get('ref', line), line.get(
'ref', line),
repr(err))) repr(err)))
return result_set return result_set

View File

@@ -31,6 +31,7 @@ except:
class GenericFileParser(FileParser): class GenericFileParser(FileParser):
""" """
Standard parser that use a define format in csv or xls to import into a 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 bank statement. This is mostely an example of how to proceed to create a new
@@ -38,7 +39,8 @@ class GenericFileParser(FileParser):
""" """
def __init__(self, parse_name, ftype='csv', **kwargs): def __init__(self, parse_name, ftype='csv', **kwargs):
super(GenericFileParser, self).__init__(parse_name, ftype=ftype, **kwargs) super(GenericFileParser, self).__init__(
parse_name, ftype=ftype, **kwargs)
@classmethod @classmethod
def parser_for(cls, parser_name): def parser_for(cls, parser_name):

View File

@@ -35,6 +35,7 @@ def UnicodeDictReader(utf8_data, **kwargs):
class BankStatementImportParser(object): class BankStatementImportParser(object):
""" """
Generic abstract class for defining parser for different files and Generic abstract class for defining parser for different files and
format to import in a bank statement. Inherit from it to create your format to import in a bank statement. Inherit from it to create your

View File

@@ -46,7 +46,8 @@ class AccountStatementProfil(Model):
help="Tic that box to automatically launch the completion " help="Tic that box to automatically launch the completion "
"on each imported file using this profile."), "on each imported file using this profile."),
'last_import_date': fields.datetime("Last Import Date"), 'last_import_date': fields.datetime("Last Import Date"),
# we remove deprecated as it floods logs in standard/warning level sob... # we remove deprecated as it floods logs in standard/warning level
# sob...
'rec_log': fields.text('log', readonly=True), # Deprecated 'rec_log': fields.text('log', readonly=True), # Deprecated
'import_type': fields.selection( 'import_type': fields.selection(
__get_import_type_selection, __get_import_type_selection,
@@ -91,7 +92,7 @@ class AccountStatementProfil(Model):
context=context) context=context)
return True return True
#Deprecated remove on V8 # Deprecated remove on V8
def prepare_statetement_lines_vals(self, *args, **kwargs): def prepare_statetement_lines_vals(self, *args, **kwargs):
return self.prepare_statement_lines_vals(*args, **kwargs) return self.prepare_statement_lines_vals(*args, **kwargs)
@@ -121,11 +122,13 @@ class AccountStatementProfil(Model):
else: else:
# This is awfully slow... # This is awfully slow...
periods = self.pool.get('account.period').find(cr, uid, periods = self.pool.get('account.period').find(cr, uid,
dt=values.get('date'), dt=values.get(
'date'),
context=context) context=context)
values['period_id'] = periods[0] values['period_id'] = periods[0]
period_memoizer[date] = periods[0] period_memoizer[date] = periods[0]
values = statement_line_obj._add_missing_default_values(cr, uid, values, context) values = statement_line_obj._add_missing_default_values(
cr, uid, values, context)
return values return values
def prepare_statement_vals(self, cr, uid, profile_id, result_row_list, def prepare_statement_vals(self, cr, uid, profile_id, result_row_list,
@@ -199,7 +202,8 @@ class AccountStatementProfil(Model):
_("Column %s you try to import is not " _("Column %s you try to import is not "
"present in the bank statement line!") % col) "present in the bank statement line!") % col)
statement_vals = self.prepare_statement_vals(cr, uid, prof.id, result_row_list, parser, context) statement_vals = self.prepare_statement_vals(
cr, uid, prof.id, result_row_list, parser, context)
statement_id = statement_obj.create(cr, uid, statement_id = statement_obj.create(cr, uid,
statement_vals, statement_vals,
context=context) context=context)
@@ -214,7 +218,8 @@ class AccountStatementProfil(Model):
context) context)
statement_store.append(values) statement_store.append(values)
# Hack to bypass ORM poor perfomance. Sob... # Hack to bypass ORM poor perfomance. Sob...
statement_line_obj._insert_lines(cr, uid, statement_store, context=context) statement_line_obj._insert_lines(
cr, uid, statement_store, context=context)
self._write_extra_statement_lines( self._write_extra_statement_lines(
cr, uid, parser, result_row_list, prof, statement_id, context) cr, uid, parser, result_row_list, prof, statement_id, context)
@@ -222,7 +227,8 @@ class AccountStatementProfil(Model):
start_bal = statement_obj.read( start_bal = statement_obj.read(
cr, uid, statement_id, ['balance_start'], context=context) cr, uid, statement_id, ['balance_start'], context=context)
start_bal = start_bal['balance_start'] start_bal = start_bal['balance_start']
statement_obj.write(cr, uid, [statement_id], {'balance_start': start_bal}) statement_obj.write(
cr, uid, [statement_id], {'balance_start': start_bal})
attachment_data = { attachment_data = {
'name': 'statement file', 'name': 'statement file',
@@ -235,7 +241,8 @@ class AccountStatementProfil(Model):
# If user ask to launch completion at end of import, do it! # If user ask to launch completion at end of import, do it!
if prof.launch_import_completion: if prof.launch_import_completion:
statement_obj.button_auto_completion(cr, uid, [statement_id], context) statement_obj.button_auto_completion(
cr, uid, [statement_id], context)
# Write the needed log infos on profile # Write the needed log infos on profile
self.write_logs_after_import(cr, uid, prof.id, self.write_logs_after_import(cr, uid, prof.id,
@@ -245,11 +252,12 @@ class AccountStatementProfil(Model):
except Exception: except Exception:
error_type, error_value, trbk = sys.exc_info() error_type, error_value, trbk = sys.exc_info()
st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value) st = "Error: %s\nDescription: %s\nTraceback:" % (
error_type.__name__, error_value)
st += ''.join(traceback.format_tb(trbk, 30)) st += ''.join(traceback.format_tb(trbk, 30))
#TODO we should catch correctly the exception with a python # TODO we should catch correctly the exception with a python
#Exception and only re-catch some special exception. # Exception and only re-catch some special exception.
#For now we avoid re-catching error in debug mode # For now we avoid re-catching error in debug mode
if config['debug_mode']: if config['debug_mode']:
raise raise
raise osv.except_osv(_("Statement import error"), raise osv.except_osv(_("Statement import error"),

View File

@@ -31,8 +31,10 @@ class test_coda_import(common.TransactionCase):
def prepare(self): def prepare(self):
self.company_a = self.browse_ref('base.main_company') self.company_a = self.browse_ref('base.main_company')
self.profile_obj = self.registry("account.statement.profile") self.profile_obj = self.registry("account.statement.profile")
self.account_bank_statement_obj = self.registry("account.bank.statement") self.account_bank_statement_obj = self.registry(
# create the 2009 fiscal year since imported coda file reference statement lines in 2009 "account.bank.statement")
# create the 2009 fiscal year since imported coda file reference
# statement lines in 2009
self.fiscalyear_id = self._create_fiscalyear("2011", self.company_a.id) self.fiscalyear_id = self._create_fiscalyear("2011", self.company_a.id)
self.account_id = self.ref("account.a_recv") self.account_id = self.ref("account.a_recv")
@@ -71,15 +73,18 @@ class test_coda_import(common.TransactionCase):
'input_statement': base64.b64encode(content), 'input_statement': base64.b64encode(content),
'file_name': os.path.basename(file_name), 'file_name': os.path.basename(file_name),
}) })
res = self.import_wizard_obj.import_statement(self.cr, self.uid, wizard_id) res = self.import_wizard_obj.import_statement(
statement_id = self.account_bank_statement_obj.search(self.cr, self.uid, eval(res['domain'])) self.cr, self.uid, wizard_id)
statement_id = self.account_bank_statement_obj.search(
self.cr, self.uid, eval(res['domain']))
return self.account_bank_statement_obj.browse(self.cr, self.uid, statement_id)[0] return self.account_bank_statement_obj.browse(self.cr, self.uid, statement_id)[0]
def test_simple_xls(self): def test_simple_xls(self):
"""Test import from xls """Test import from xls
""" """
self.prepare() self.prepare()
file_name = self._filename_to_abs_filename(os.path.join("..", "data", "statement.xls")) file_name = self._filename_to_abs_filename(
os.path.join("..", "data", "statement.xls"))
statement = self._import_file(file_name) statement = self._import_file(file_name)
self._validate_imported_satement(statement) self._validate_imported_satement(statement)
@@ -87,7 +92,8 @@ class test_coda_import(common.TransactionCase):
"""Test import from csv """Test import from csv
""" """
self.prepare() self.prepare()
file_name = self._filename_to_abs_filename(os.path.join("..", "data", "statement.csv")) file_name = self._filename_to_abs_filename(
os.path.join("..", "data", "statement.csv"))
statement = self._import_file(file_name) statement = self._import_file(file_name)
self._validate_imported_satement(statement) self._validate_imported_satement(statement)

View File

@@ -39,9 +39,11 @@ class CreditPartnerStatementImporter(orm.TransientModel):
if (context.get('active_model', False) == 'account.statement.profile' and if (context.get('active_model', False) == 'account.statement.profile' and
context.get('active_ids', False)): context.get('active_ids', False)):
ids = context['active_ids'] ids = context['active_ids']
assert len(ids) == 1, 'You cannot use this on more than one profile !' assert len(
ids) == 1, 'You cannot use this on more than one profile !'
res['profile_id'] = ids[0] res['profile_id'] = ids[0]
other_vals = self.onchange_profile_id(cr, uid, [], res['profile_id'], context=context) other_vals = self.onchange_profile_id(
cr, uid, [], res['profile_id'], context=context)
res.update(other_vals.get('value', {})) res.update(other_vals.get('value', {}))
return res return res
@@ -86,7 +88,7 @@ class CreditPartnerStatementImporter(orm.TransientModel):
def _check_extension(self, filename): def _check_extension(self, filename):
(__, ftype) = os.path.splitext(filename) (__, ftype) = os.path.splitext(filename)
if not ftype: if not ftype:
#We do not use osv exception we do not want to have it logged # We do not use osv exception we do not want to have it logged
raise Exception(_('Please use a file with an extention')) raise Exception(_('Please use a file with an extention'))
return ftype return ftype
@@ -110,7 +112,8 @@ class CreditPartnerStatementImporter(orm.TransientModel):
) )
model_obj = self.pool.get('ir.model.data') model_obj = self.pool.get('ir.model.data')
action_obj = self.pool.get('ir.actions.act_window') action_obj = self.pool.get('ir.actions.act_window')
action_id = model_obj.get_object_reference(cr, uid, 'account', 'action_bank_statement_tree')[1] action_id = model_obj.get_object_reference(
cr, uid, 'account', 'action_bank_statement_tree')[1]
res = action_obj.read(cr, uid, action_id) res = action_obj.read(cr, uid, action_id)
res['domain'] = res['domain'][:-1] + ",('id', 'in', %s)]" % sid res['domain'] = res['domain'][:-1] + ",('id', 'in', %s)]" % sid
return res return res

View File

@@ -34,14 +34,14 @@
This module brings commission support to bank statement imports. It computes the sum of a commission 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. field on each transaction and creates a statement entry for it.
""", """,
'website': 'http://www.camptocamp.com', 'website': 'http://www.camptocamp.com',
'data': [ 'data': [
"statement_view.xml", "statement_view.xml",
"import_statement_view.xml", "import_statement_view.xml",
], ],
'test': [], 'test': [],
'installable': True, 'installable': True,
'images': [], 'images': [],
'auto_install': False, 'auto_install': False,
'license': 'AGPL-3', 'license': 'AGPL-3',
} }

View File

@@ -16,7 +16,8 @@ class AccountStatementProfil(orm.Model):
""" """
global_commission_amount = 0 global_commission_amount = 0
for row in parser.result_row_list: for row in parser.result_row_list:
global_commission_amount += float_or_zero(row.get('commission_amount', '0.0')) global_commission_amount += float_or_zero(
row.get('commission_amount', '0.0'))
if not global_commission_amount: if not global_commission_amount:
return return
partner_id = profile.partner_id and profile.partner_id.id or False partner_id = profile.partner_id and profile.partner_id.id or False

View File

@@ -22,4 +22,3 @@
from . import partner from . import partner
from . import statement from . import statement

View File

@@ -46,4 +46,3 @@
'installable': True, 'installable': True,
'active': False, 'active': False,
} }

View File

@@ -26,10 +26,12 @@ from openerp.addons.account_statement_base_completion.statement import ErrorTooM
class ErrorTooManyLabel(Exception): class ErrorTooManyLabel(Exception):
""" """
New Exception definition that is raised when more than one label is matched New Exception definition that is raised when more than one label is matched
by the completion rule. by the completion rule.
""" """
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
@@ -38,6 +40,7 @@ class ErrorTooManyLabel(Exception):
class AccountBankSatement(orm.Model): class AccountBankSatement(orm.Model):
""" """
We add a basic button and stuff to support the auto-completion We add a basic button and stuff to support the auto-completion
of the bank statement once line have been imported or manually fullfill. of the bank statement once line have been imported or manually fullfill.
@@ -114,6 +117,7 @@ class AccountStatementCompletionRule(orm.Model):
class AccountStatementLabel(orm.Model): class AccountStatementLabel(orm.Model):
"""Create a new class to map an account statement label to a partner """Create a new class to map an account statement label to a partner
and a specific account and a specific account
""" """
@@ -125,7 +129,7 @@ class AccountStatementLabel(orm.Model):
'partner_id': fields.many2one('res.partner', 'Partner'), 'partner_id': fields.many2one('res.partner', 'Partner'),
'label': fields.char('Bank Statement Label', size=100), 'label': fields.char('Bank Statement Label', size=100),
'account_id': fields.many2one('account.account', 'Account', 'account_id': fields.many2one('account.account', 'Account',
required = True, required=True,
help='Account corresponding to the label ' help='Account corresponding to the label '
'for a given partner'), 'for a given partner'),
'company_id': fields.related('account_id', 'company_id', 'company_id': fields.related('account_id', 'company_id',
@@ -139,7 +143,7 @@ class AccountStatementLabel(orm.Model):
} }
_defaults = { _defaults = {
'company_id': lambda s,cr,uid,c: 'company_id': lambda s, cr, uid, c:
s.pool.get('res.company')._company_default_get(cr, uid, s.pool.get('res.company')._company_default_get(cr, uid,
'account.statement.label', 'account.statement.label',
context=c), context=c),

View File

@@ -43,4 +43,4 @@
'images': [], 'images': [],
'auto_install': False, 'auto_install': False,
'license': 'AGPL-3', 'license': 'AGPL-3',
} }

View File

@@ -28,7 +28,8 @@ from openerp.addons.report_webkit import webkit_report
class BankStatementWebkit(report_sxw.rml_parse): class BankStatementWebkit(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context): def __init__(self, cr, uid, name, context):
super(BankStatementWebkit, self).__init__(cr, uid, name, context=context) super(BankStatementWebkit, self).__init__(
cr, uid, name, context=context)
self.pool = pooler.get_pool(self.cr.dbname) self.pool = pooler.get_pool(self.cr.dbname)
self.cursor = self.cr self.cursor = self.cr
@@ -36,7 +37,8 @@ class BankStatementWebkit(report_sxw.rml_parse):
self.cr, uid, uid, context=context).company_id self.cr, uid, uid, context=context).company_id
header_report_name = ' - '.join((_('BORDEREAU DE REMISE DE CHEQUES'), header_report_name = ' - '.join((_('BORDEREAU DE REMISE DE CHEQUES'),
company.name, company.currency_id.name)) company.name, company.currency_id.name))
footer_date_time = self.formatLang(str(datetime.today())[:19], date_time=True) footer_date_time = self.formatLang(
str(datetime.today())[:19], date_time=True)
self.localcontext.update({ self.localcontext.update({
'cr': cr, 'cr': cr,
'uid': uid, 'uid': uid,
@@ -50,7 +52,8 @@ class BankStatementWebkit(report_sxw.rml_parse):
('--header-left', header_report_name), ('--header-left', header_report_name),
('--header-spacing', '2'), ('--header-spacing', '2'),
('--footer-left', footer_date_time), ('--footer-left', footer_date_time),
('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))), ('--footer-right',
' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
('--footer-line',), ('--footer-line',),
], ],
}) })

View File

@@ -40,6 +40,7 @@ stat_mod.account_bank_statement.write = fixed_write
class AccountStatementProfile(Model): class AccountStatementProfile(Model):
""" """
A Profile will contain all infos related to the type of A Profile will contain all infos related to the type of
bank statement, and related generated entries. It defines the bank statement, and related generated entries. It defines the
@@ -110,16 +111,18 @@ class AccountStatementProfile(Model):
return True return True
_constraints = [ _constraints = [
(_check_partner, "You need to put a partner if you tic the 'Force partner on bank move'!", []), (_check_partner,
"You need to put a partner if you tic the 'Force partner on bank move'!", []),
] ]
_sql_constraints = [ _sql_constraints = [
('name_uniq', 'unique (name, company_id)', 'The name of the bank statement must be unique !') ('name_uniq', 'unique (name, company_id)',
'The name of the bank statement must be unique !')
] ]
class AccountBankStatement(Model): class AccountBankStatement(Model):
""" """
We improve the bank statement class mostly for : We improve the bank statement class mostly for :
- Removing the period and compute it from the date of each line. - Removing the period and compute it from the date of each line.
@@ -140,7 +143,8 @@ class AccountBankStatement(Model):
if context is None: if context is None:
context = {} context = {}
period_obj = self.pool.get('account.period') period_obj = self.pool.get('account.period')
periods = period_obj.find(cr, uid, dt=context.get('date'), context=context) periods = period_obj.find(
cr, uid, dt=context.get('date'), context=context)
return periods and periods[0] or False return periods and periods[0] or False
def _default_profile(self, cr, uid, context=None): def _default_profile(self, cr, uid, context=None):
@@ -155,7 +159,8 @@ class AccountBankStatement(Model):
user_obj = self.pool.get('res.users') user_obj = self.pool.get('res.users')
profile_obj = self.pool.get('account.statement.profile') profile_obj = self.pool.get('account.statement.profile')
user = user_obj.browse(cr, uid, uid, context=context) user = user_obj.browse(cr, uid, uid, context=context)
profile_ids = profile_obj.search(cr, uid, [('company_id', '=', user.company_id.id)], context=context) profile_ids = profile_obj.search(
cr, uid, [('company_id', '=', user.company_id.id)], context=context)
return profile_ids[0] if profile_ids else False return profile_ids[0] if profile_ids else False
@@ -236,7 +241,8 @@ class AccountBankStatement(Model):
need it.""" need it."""
if 'profile_id' in vals: if 'profile_id' in vals:
profile_obj = self.pool.get('account.statement.profile') profile_obj = self.pool.get('account.statement.profile')
profile = profile_obj.browse(cr, uid, vals['profile_id'], context=context) profile = profile_obj.browse(
cr, uid, vals['profile_id'], context=context)
vals['journal_id'] = profile.journal_id.id vals['journal_id'] = profile.journal_id.id
return super(AccountBankStatement, self return super(AccountBankStatement, self
).create(cr, uid, vals, context=context) ).create(cr, uid, vals, context=context)
@@ -363,15 +369,18 @@ class AccountBankStatement(Model):
""" """
year = self.pool.get('account.period').browse( year = self.pool.get('account.period').browse(
cr, uid, self._get_period(cr, uid, date)).fiscalyear_id.id cr, uid, self._get_period(cr, uid, date)).fiscalyear_id.id
profile = self.pool.get('account.statement.profile').browse(cr, uid, profile_id) profile = self.pool.get(
'account.statement.profile').browse(cr, uid, profile_id)
c = {'fiscalyear_id': year} c = {'fiscalyear_id': year}
obj_seq = self.pool.get('ir.sequence') obj_seq = self.pool.get('ir.sequence')
journal_sequence_id = (profile.journal_id.sequence_id and journal_sequence_id = (profile.journal_id.sequence_id and
profile.journal_id.sequence_id.id or False) profile.journal_id.sequence_id.id or False)
if journal_sequence_id: if journal_sequence_id:
st_number = obj_seq.next_by_id(cr, uid, journal_sequence_id, context=c) st_number = obj_seq.next_by_id(
cr, uid, journal_sequence_id, context=c)
else: else:
st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=c) st_number = obj_seq.next_by_code(
cr, uid, 'account.bank.statement', context=c)
if profile.bank_statement_prefix: if profile.bank_statement_prefix:
st_number = profile.bank_statement_prefix + st_number st_number = profile.bank_statement_prefix + st_number
return st_number return st_number
@@ -393,7 +402,8 @@ class AccountBankStatement(Model):
if not self.check_status_condition(cr, uid, st.state, journal_type=j_type): if not self.check_status_condition(cr, uid, st.state, journal_type=j_type):
continue continue
self.balance_check(cr, uid, st.id, journal_type=j_type, context=context) self.balance_check(
cr, uid, st.id, journal_type=j_type, context=context)
if (not st.journal_id.default_credit_account_id) \ if (not st.journal_id.default_credit_account_id) \
or (not st.journal_id.default_debit_account_id): or (not st.journal_id.default_debit_account_id):
raise osv.except_osv(_('Configuration Error!'), raise osv.except_osv(_('Configuration Error!'),
@@ -402,8 +412,9 @@ class AccountBankStatement(Model):
if not st.name == '/': if not st.name == '/':
st_number = st.name st_number = st.name
else: else:
# Begin Changes # Begin Changes
st_number = self._get_st_number_period_profile(cr, uid, st.date, st.profile_id.id) st_number = self._get_st_number_period_profile(
cr, uid, st.date, st.profile_id.id)
# End Changes # End Changes
for line in st.move_line_ids: for line in st.move_line_ids:
if line.state != 'valid': if line.state != 'valid':
@@ -420,16 +431,19 @@ class AccountBankStatement(Model):
" journal on the '%s' journal!") % st.journal_id.name) " journal on the '%s' journal!") % st.journal_id.name)
if not st_line.amount: if not st_line.amount:
continue continue
st_line_number = self.get_next_st_line_number(cr, uid, st_number, st_line, context) st_line_number = self.get_next_st_line_number(
cr, uid, st_number, st_line, context)
self.create_move_from_st_line(cr, uid, st_line.id, self.create_move_from_st_line(cr, uid, st_line.id,
company_currency_id, company_currency_id,
st_line_number, st_line_number,
context) context)
except osv.except_osv, exc: except osv.except_osv, exc:
msg = "Line ID %s with ref %s had following error: %s" % (st_line.id, st_line.ref, exc.value) msg = "Line ID %s with ref %s had following error: %s" % (
st_line.id, st_line.ref, exc.value)
errors_stack.append(msg) errors_stack.append(msg)
except Exception, exc: except Exception, exc:
msg = "Line ID %s with ref %s had following error: %s" % (st_line.id, st_line.ref, str(exc)) msg = "Line ID %s with ref %s had following error: %s" % (
st_line.id, st_line.ref, str(exc))
errors_stack.append(msg) errors_stack.append(msg)
if errors_stack: if errors_stack:
msg = u"\n".join(errors_stack) msg = u"\n".join(errors_stack)
@@ -439,7 +453,8 @@ class AccountBankStatement(Model):
{'name': st_number, {'name': st_number,
'balance_end_real': st.balance_end}, 'balance_end_real': st.balance_end},
context=context) context=context)
body = _('Statement %s confirmed, journal items were created.') % st_number body = _(
'Statement %s confirmed, journal items were created.') % st_number
self.message_post(cr, uid, [st.id], self.message_post(cr, uid, [st.id],
body, body,
context=context) context=context)
@@ -515,7 +530,8 @@ class AccountBankStatement(Model):
as 'customer' or 'supplier'. as 'customer' or 'supplier'.
""" """
account_id = False account_id = False
ltype = self.get_type_for_counterpart(cr, uid, amount, partner_id=partner_id) ltype = self.get_type_for_counterpart(
cr, uid, amount, partner_id=partner_id)
if ltype == 'supplier': if ltype == 'supplier':
account_id = account_payable account_id = account_payable
else: else:
@@ -581,6 +597,7 @@ class AccountBankStatement(Model):
class AccountBankStatementLine(Model): class AccountBankStatementLine(Model):
""" """
Override to compute the period from the date of the line, add a method to retrieve Override to compute the period from the date of the line, add a method to retrieve
the values for a line from the profile. Override the on_change method to take care of the values for a line from the profile. Override the on_change method to take care of
@@ -684,7 +701,8 @@ class AccountBankStatementLine(Model):
receiv_account = part.property_account_receivable.id receiv_account = part.property_account_receivable.id
# If no value, look on the default company property # If no value, look on the default company property
if not pay_account or not receiv_account: if not pay_account or not receiv_account:
receiv_account, pay_account = obj_stat.get_default_pay_receiv_accounts(cr, uid, context=None) receiv_account, pay_account = obj_stat.get_default_pay_receiv_accounts(
cr, uid, context=None)
account_id, comp_line_type = obj_stat.get_account_and_type_for_counterpart(cr, uid, amount, account_id, comp_line_type = obj_stat.get_account_and_type_for_counterpart(cr, uid, amount,
receiv_account, pay_account, receiv_account, pay_account,
partner_id=partner_id) partner_id=partner_id)
@@ -702,8 +720,10 @@ class AccountBankStatementLine(Model):
obj_stat = self.pool.get('account.bank.statement') obj_stat = self.pool.get('account.bank.statement')
if not partner_id: if not partner_id:
return {} return {}
line_type = obj_stat.get_type_for_counterpart(cr, uid, 0.0, partner_id=partner_id) line_type = obj_stat.get_type_for_counterpart(
res_type = self.onchange_type(cr, uid, ids, partner_id, line_type, profile_id, context=context) cr, uid, 0.0, partner_id=partner_id)
res_type = self.onchange_type(
cr, uid, ids, partner_id, line_type, profile_id, context=context)
if res_type['value'] and res_type['value'].get('account_id', False): if res_type['value'] and res_type['value'].get('account_id', False):
return {'value': {'type': line_type, return {'value': {'type': line_type,
'account_id': res_type['value']['account_id'], 'account_id': res_type['value']['account_id'],

View File

@@ -36,17 +36,18 @@ if not hasattr(std_pos_session, '_prepare_bank_statement'):
# This change has been proposed for merging to fix lp:125375 # This change has been proposed for merging to fix lp:125375
def mp_prepare_bank_statement(self, cr, uid, pos_config, journal, context=None): def mp_prepare_bank_statement(self, cr, uid, pos_config, journal, context=None):
bank_values = { bank_values = {
'journal_id' : journal.id, 'journal_id': journal.id,
'user_id' : uid, 'user_id': uid,
'company_id' : pos_config.shop_id.company_id.id 'company_id': pos_config.shop_id.company_id.id
} }
return bank_values return bank_values
def mp_create(self, cr, uid, values, context=None): def mp_create(self, cr, uid, values, context=None):
context = context or {} context = context or {}
config_id = values.get('config_id', False) or context.get('default_config_id', False) config_id = values.get('config_id', False) or context.get(
'default_config_id', False)
if not config_id: if not config_id:
raise osv.except_osv( _('Error!'), raise osv.except_osv(_('Error!'),
_("You should assign a Point of Sale to your session.")) _("You should assign a Point of Sale to your session."))
# journal_id is not required on the pos_config because it does not # journal_id is not required on the pos_config because it does not
@@ -57,35 +58,42 @@ if not hasattr(std_pos_session, '_prepare_bank_statement'):
pos_config = jobj.browse(cr, uid, config_id, context=context) pos_config = jobj.browse(cr, uid, config_id, context=context)
context.update({'company_id': pos_config.shop_id.company_id.id}) context.update({'company_id': pos_config.shop_id.company_id.id})
if not pos_config.journal_id: if not pos_config.journal_id:
jid = jobj.default_get(cr, uid, ['journal_id'], context=context)['journal_id'] jid = jobj.default_get(
cr, uid, ['journal_id'], context=context)['journal_id']
if jid: if jid:
jobj.write(cr, uid, [pos_config.id], {'journal_id': jid}, context=context) jobj.write(
cr, uid, [pos_config.id], {'journal_id': jid}, context=context)
else: else:
raise osv.except_osv( _('error!'), raise osv.except_osv(_('error!'),
_("Unable to open the session. You have to assign a sale journal to your point of sale.")) _("Unable to open the session. You have to assign a sale journal to your point of sale."))
# define some cash journal if no payment method exists # define some cash journal if no payment method exists
if not pos_config.journal_ids: if not pos_config.journal_ids:
journal_proxy = self.pool.get('account.journal') journal_proxy = self.pool.get('account.journal')
cashids = journal_proxy.search(cr, uid, [('journal_user', '=', True), ('type','=','cash')], context=context) cashids = journal_proxy.search(
cr, uid, [('journal_user', '=', True), ('type', '=', 'cash')], context=context)
if not cashids: if not cashids:
cashids = journal_proxy.search(cr, uid, [('type', '=', 'cash')], context=context) cashids = journal_proxy.search(
cr, uid, [('type', '=', 'cash')], context=context)
if not cashids: if not cashids:
cashids = journal_proxy.search(cr, uid, [('journal_user','=',True)], context=context) cashids = journal_proxy.search(
cr, uid, [('journal_user', '=', True)], context=context)
jobj.write(cr, uid, [pos_config.id], {'journal_ids': [(6,0, cashids)]})
jobj.write(
cr, uid, [pos_config.id], {'journal_ids': [(6, 0, cashids)]})
pos_config = jobj.browse(cr, uid, config_id, context=context) pos_config = jobj.browse(cr, uid, config_id, context=context)
bank_statement_ids = [] bank_statement_ids = []
for journal in pos_config.journal_ids: for journal in pos_config.journal_ids:
bank_values = self._prepare_bank_statement(cr, uid, pos_config, journal, context) bank_values = self._prepare_bank_statement(
statement_id = self.pool.get('account.bank.statement').create(cr, uid, bank_values, context=context) cr, uid, pos_config, journal, context)
statement_id = self.pool.get('account.bank.statement').create(
cr, uid, bank_values, context=context)
bank_statement_ids.append(statement_id) bank_statement_ids.append(statement_id)
values.update({ values.update({
'name' : pos_config.sequence_id._next(), 'name': pos_config.sequence_id._next(),
'statement_ids' : [(6, 0, bank_statement_ids)], 'statement_ids': [(6, 0, bank_statement_ids)],
'config_id': config_id 'config_id': config_id
}) })
return super(std_pos_session, self).create(cr, uid, values, context=context) return super(std_pos_session, self).create(cr, uid, values, context=context)
@@ -111,7 +119,8 @@ class pos_session(orm.Model):
profile_obj = self.pool.get('account.statement.profile') profile_obj = self.pool.get('account.statement.profile')
user = user_obj.browse(cr, uid, uid, context=context) user = user_obj.browse(cr, uid, uid, context=context)
defaults = self.pool['account.bank.statement'].default_get(cr, uid, defaults = self.pool['account.bank.statement'].default_get(cr, uid,
['profile_id', 'period_id'], ['profile_id',
'period_id'],
context=context) context=context)
profile_ids = profile_obj.search(cr, uid, profile_ids = profile_obj.search(cr, uid,
[('company_id', '=', user.company_id.id), [('company_id', '=', user.company_id.id),

View File

@@ -49,4 +49,4 @@
'auto_install': False, 'auto_install': False,
'license': 'AGPL-3', 'license': 'AGPL-3',
} }

View File

@@ -19,4 +19,3 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################### ###############################################################################

View File

@@ -46,4 +46,4 @@
'images': [], 'images': [],
'auto_install': False, 'auto_install': False,
'license': 'AGPL-3', 'license': 'AGPL-3',
} }

View File

@@ -19,4 +19,3 @@
# #
############################################################################## ##############################################################################
from . import ofx_parser from . import ofx_parser

View File

@@ -30,7 +30,9 @@ try:
except: except:
raise Exception(_('Please install python lib ofxparse')) raise Exception(_('Please install python lib ofxparse'))
class OfxParser(BankStatementImportParser): class OfxParser(BankStatementImportParser):
"""Class for defining parser for OFX file format.""" """Class for defining parser for OFX file format."""
@classmethod @classmethod
@@ -110,4 +112,3 @@ class OfxParser(BankStatementImportParser):
'ref': line.get('ref', '/'), 'ref': line.get('ref', '/'),
'label': line.get('label', ''), 'label': line.get('label', ''),
} }

View File

@@ -21,6 +21,7 @@
from openerp.tools.translate import _ from openerp.tools.translate import _
from openerp.osv import fields, orm from openerp.osv import fields, orm
class AccountStatementProfil(orm.Model): class AccountStatementProfil(orm.Model):
_inherit = "account.statement.profile" _inherit = "account.statement.profile"

View File

@@ -36,6 +36,7 @@ class AccountStatementProfile(orm.Model):
"for the refunds and one for the payments.") "for the refunds and one for the payments.")
} }
class account_bank_statement(orm.Model): class account_bank_statement(orm.Model):
_inherit = "account.bank.statement" _inherit = "account.bank.statement"
@@ -52,7 +53,6 @@ class account_bank_statement(orm.Model):
}) })
return res return res
return res return res
def _prepare_move(self, cr, uid, st_line, st_line_number, context=None): def _prepare_move(self, cr, uid, st_line, st_line_number, context=None):
@@ -65,22 +65,25 @@ class account_bank_statement(orm.Model):
}) })
return res 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): st_line_number, context=None):
if context is None: if context is None:
context = {} context = {}
context['from_parent_object'] = True #For compability with module account_constraints # For compability with module account_constraints
context['from_parent_object'] = True
account_move_obj = self.pool.get('account.move') account_move_obj = self.pool.get('account.move')
account_bank_statement_line_obj = self.pool.get('account.bank.statement.line') account_bank_statement_line_obj = self.pool.get(
'account.bank.statement.line')
st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id, st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id,
context=context) context=context)
st = st_line.statement_id st = st_line.statement_id
if st.profile_id.one_move: if st.profile_id.one_move:
if not context.get('move_id'): if not context.get('move_id'):
move_vals = self._prepare_move(cr, uid, st_line, st_line_number, context=context) move_vals = self._prepare_move(
context['move_id'] = account_move_obj.create(cr, uid, move_vals, context=context) cr, uid, st_line, st_line_number, context=context)
context['move_id'] = account_move_obj.create(
cr, uid, move_vals, context=context)
self.create_move_line_from_st_line(cr, uid, context['move_id'], self.create_move_line_from_st_line(cr, uid, context['move_id'],
st_line_id, company_currency_id, st_line_id, company_currency_id,
context=context) context=context)
@@ -104,12 +107,15 @@ class account_bank_statement(orm.Model):
context = {} context = {}
res_currency_obj = self.pool.get('res.currency') res_currency_obj = self.pool.get('res.currency')
account_move_line_obj = self.pool.get('account.move.line') account_move_line_obj = self.pool.get('account.move.line')
account_bank_statement_line_obj = self.pool.get('account.bank.statement.line') account_bank_statement_line_obj = self.pool.get(
st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id, context=context) 'account.bank.statement.line')
st_line = account_bank_statement_line_obj.browse(
cr, uid, st_line_id, context=context)
st = st_line.statement_id st = st_line.statement_id
context.update({'date': st_line.date}) context.update({'date': st_line.date})
acc_cur = ((st_line.amount<=0) and st.journal_id.default_debit_account_id) or st_line.account_id acc_cur = ((st_line.amount <= 0)
and st.journal_id.default_debit_account_id) or st_line.account_id
context.update({ context.update({
'res.currency.compute.account': acc_cur, 'res.currency.compute.account': acc_cur,
@@ -129,7 +135,6 @@ class account_bank_statement(orm.Model):
move_obj.post(cr, uid, [move_id], context=context) move_obj.post(cr, uid, [move_id], context=context)
return True return True
def _prepare_transfer_move_line_vals(self, cr, uid, st, name, amount, move_id, context=None): def _prepare_transfer_move_line_vals(self, cr, uid, st, name, amount, move_id, context=None):
""" """
Prepare the dict of values to create the transfer move lines. Prepare the dict of values to create the transfer move lines.
@@ -157,7 +162,6 @@ class account_bank_statement(orm.Model):
} }
return vals return vals
def create_move_transfer_lines(self, cr, uid, move, st, context=None): def create_move_transfer_lines(self, cr, uid, move, st, context=None):
move_line_obj = self.pool.get('account.move.line') move_line_obj = self.pool.get('account.move.line')
move_id = move.id move_id = move.id
@@ -165,11 +169,11 @@ class account_bank_statement(orm.Model):
payment = 0.0 payment = 0.0
transfer_lines = [] transfer_lines = []
transfer_line_ids = [] transfer_line_ids = []
#Calculate the part of the refund amount and the payment amount # Calculate the part of the refund amount and the payment amount
for move_line in move.line_id: for move_line in move.line_id:
refund -= move_line.debit refund -= move_line.debit
payment += move_line.credit payment += move_line.credit
#Create 2 Transfer lines or One global tranfer line # Create 2 Transfer lines or One global tranfer line
if st.profile_id.split_transfer_line: if st.profile_id.split_transfer_line:
if refund: if refund:
transfer_lines.append(['Refund Transfer', refund]) transfer_lines.append(['Refund Transfer', refund])
@@ -185,10 +189,10 @@ class account_bank_statement(orm.Model):
transfer_line[1], transfer_line[1],
move_id, move_id,
context=context) context=context)
transfer_line_ids.append(move_line_obj.create(cr, uid, vals, context=context)) transfer_line_ids.append(
move_line_obj.create(cr, uid, vals, context=context))
return transfer_line_ids return transfer_line_ids
def button_confirm_bank(self, cr, uid, ids, context=None): def button_confirm_bank(self, cr, uid, ids, context=None):
st_line_obj = self.pool.get('account.bank.statement.line') st_line_obj = self.pool.get('account.bank.statement.line')
move_obj = self.pool.get('account.move') move_obj = self.pool.get('account.move')
@@ -200,7 +204,8 @@ class account_bank_statement(orm.Model):
if st.profile_id.one_move and context.get('move_id', False): if st.profile_id.one_move and context.get('move_id', False):
move_id = context['move_id'] move_id = context['move_id']
move = move_obj.browse(cr, uid, move_id, context=context) move = move_obj.browse(cr, uid, move_id, context=context)
transfe_line_ids = self.create_move_transfer_lines(cr, uid, move, st, context=context) transfe_line_ids = self.create_move_transfer_lines(
cr, uid, move, st, context=context)
self._valid_move(cr, uid, move_id, context=context) self._valid_move(cr, uid, move_id, context=context)
lines_ids = [x.id for x in st.line_ids] lines_ids = [x.id for x in st.line_ids]
st_line_obj.write(cr, uid, lines_ids, st_line_obj.write(cr, uid, lines_ids,
@@ -216,10 +221,8 @@ class account_bank_statement(orm.Model):
if move.state != 'draft': if move.state != 'draft':
move.button_cancel(context=context) move.button_cancel(context=context)
move.unlink(context=context) move.unlink(context=context)
st.write({'state':'draft'}, context=context) st.write({'state': 'draft'}, context=context)
else: else:
super(account_bank_statement, self).button_cancel(cr, uid, ids, super(account_bank_statement, self).button_cancel(cr, uid, ids,
context=context) context=context)
return True return True

View File

@@ -35,6 +35,7 @@ import re
class AccountStatementCompletionRule(Model): class AccountStatementCompletionRule(Model):
"""Add a rule to complete account based on a regular expression""" """Add a rule to complete account based on a regular expression"""
_inherit = "account.statement.completion.rule" _inherit = "account.statement.completion.rule"

View File

@@ -36,14 +36,17 @@ ACC_NUMBER = "BE38733040385372"
class test_regex_account_completion(common.TransactionCase): class test_regex_account_completion(common.TransactionCase):
def prepare(self): def prepare(self):
self.account_bank_statement_obj = self.registry("account.bank.statement") self.account_bank_statement_obj = self.registry(
self.account_bank_statement_line_obj = self.registry("account.bank.statement.line") "account.bank.statement")
self.account_bank_statement_line_obj = self.registry(
"account.bank.statement.line")
self.account_id = self.ref('account.a_expense') self.account_id = self.ref('account.a_expense')
# create the completion rule # create the completion rule
rule_vals = {'function_to_call': 'set_account', rule_vals = {'function_to_call': 'set_account',
'regex': '^My statement', 'regex': '^My statement',
'account_id': self.account_id} 'account_id': self.account_id}
completion_rule_id = self.registry("account.statement.completion.rule").create(self.cr, self.uid, rule_vals) completion_rule_id = self.registry(
"account.statement.completion.rule").create(self.cr, self.uid, rule_vals)
# Create the profile # Create the profile
journal_id = self.ref("account.bank_journal") journal_id = self.ref("account.bank_journal")
@@ -83,9 +86,14 @@ class test_regex_account_completion(common.TransactionCase):
"""Test the automatic completion on account """Test the automatic completion on account
""" """
self.prepare() self.prepare()
statement_obj = self.account_bank_statement_obj.browse(self.cr, self.uid, self.statement_id) statement_obj = self.account_bank_statement_obj.browse(
self.cr, self.uid, self.statement_id)
statement_obj.button_auto_completion() statement_obj.button_auto_completion()
statement_line1 = self.account_bank_statement_line_obj.browse(self.cr, self.uid, self.statement_line1_id) statement_line1 = self.account_bank_statement_line_obj.browse(
self.assertEquals(self.account_id, statement_line1.account_id.id, "The account should be the account of the completion") self.cr, self.uid, self.statement_line1_id)
statement_line2 = self.account_bank_statement_line_obj.browse(self.cr, self.uid, self.statement_line2_id) self.assertEquals(self.account_id, statement_line1.account_id.id,
self.assertNotEqual(self.account_id, statement_line2.account_id.id, "The account should be not the account of the completion") "The account should be the account of the completion")
statement_line2 = self.account_bank_statement_line_obj.browse(
self.cr, self.uid, self.statement_line2_id)
self.assertNotEqual(self.account_id, statement_line2.account_id.id,
"The account should be not the account of the completion")

View File

@@ -58,4 +58,4 @@
'images': [], 'images': [],
'auto_install': True, 'auto_install': True,
'license': 'AGPL-3', 'license': 'AGPL-3',
} }

View File

@@ -26,6 +26,7 @@ from openerp.addons.account_statement_base_completion.statement import ErrorTooM
class AccountStatementCompletionRule(Model): class AccountStatementCompletionRule(Model):
"""Add a rule based on transaction ID""" """Add a rule based on transaction ID"""
_inherit = "account.statement.completion.rule" _inherit = "account.statement.completion.rule"
@@ -59,7 +60,8 @@ class AccountStatementCompletionRule(Model):
so_obj = self.pool.get('sale.order') so_obj = self.pool.get('sale.order')
so_id = so_obj.search(cr, so_id = so_obj.search(cr,
uid, uid,
[('transaction_id', '=', st_line['transaction_id'])], [('transaction_id', '=',
st_line['transaction_id'])],
context=context) context=context)
if len(so_id) > 1: if len(so_id) > 1:
raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched by more than ' raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched by more than '
@@ -70,11 +72,15 @@ class AccountStatementCompletionRule(Model):
res['ref'] = so.name res['ref'] = so.name
st_vals = st_obj.get_values_for_line(cr, st_vals = st_obj.get_values_for_line(cr,
uid, uid,
profile_id=st_line['profile_id'], profile_id=st_line[
master_account_id=st_line['master_account_id'], 'profile_id'],
partner_id=res.get('partner_id', False), master_account_id=st_line[
'master_account_id'],
partner_id=res.get(
'partner_id', False),
line_type=st_line['type'], line_type=st_line['type'],
amount=st_line['amount'] if st_line['amount'] else 0.0, amount=st_line['amount'] if st_line[
'amount'] else 0.0,
context=context) context=context)
res.update(st_vals) res.update(st_vals)
return res return res

View File

@@ -57,4 +57,4 @@
'images': [], 'images': [],
'auto_install': False, 'auto_install': False,
'license': 'AGPL-3', 'license': 'AGPL-3',
} }

View File

@@ -22,6 +22,7 @@ from account_statement_base_import.parser.file_parser import FileParser
class TransactionIDFileParser(FileParser): class TransactionIDFileParser(FileParser):
""" """
TransactionID parser that use a define format in csv or xls to import TransactionID parser that use a define format in csv or xls to import
bank statement. bank statement.
@@ -40,7 +41,8 @@ class TransactionIDFileParser(FileParser):
super(TransactionIDFileParser, self).__init__(profile, extra_fields=extra_fields, super(TransactionIDFileParser, self).__init__(profile, extra_fields=extra_fields,
ftype=ftype, header=header, **kwargs) ftype=ftype, header=header, **kwargs)
# ref is replaced by transaction_id thus we delete it from check # 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'] self.keys_to_validate = [
k for k in self.keys_to_validate if k != 'ref']
del self.conversion_dict['ref'] del self.conversion_dict['ref']
@classmethod @classmethod

View File

@@ -54,4 +54,4 @@
'images': [], 'images': [],
'auto_install': False, 'auto_install': False,
'license': 'AGPL-3', 'license': 'AGPL-3',
} }

View File

@@ -35,7 +35,7 @@ class SaleOrder(Model):
} }
def _prepare_invoice(self, cr, uid, order, lines, context=None): def _prepare_invoice(self, cr, uid, order, lines, context=None):
#we put the transaction id in the generated invoices # we put the transaction id in the generated invoices
invoice_vals = super(SaleOrder, self)._prepare_invoice( invoice_vals = super(SaleOrder, self)._prepare_invoice(
cr, uid, order, lines, context=context) cr, uid, order, lines, context=context)
invoice_vals.update({ invoice_vals.update({

View File

@@ -45,7 +45,8 @@ class AccountStatementFromInvoiceLines(orm.TransientModel):
statement_line_obj = self.pool.get('account.bank.statement.line') statement_line_obj = self.pool.get('account.bank.statement.line')
currency_obj = self.pool.get('res.currency') currency_obj = self.pool.get('res.currency')
line_date = time.strftime('%Y-%m-%d') line_date = time.strftime('%Y-%m-%d')
statement = statement_obj.browse(cr, uid, statement_id, context=context) statement = statement_obj.browse(
cr, uid, statement_id, context=context)
# for each selected move lines # for each selected move lines
for line in line_obj.browse(cr, uid, line_ids, context=context): for line in line_obj.browse(cr, uid, line_ids, context=context):
ctx = context.copy() ctx = context.copy()
@@ -109,11 +110,13 @@ class AccountPaymentPopulateStatement(orm.TransientModel):
if not line_ids: if not line_ids:
return {'type': 'ir.actions.act_window_close'} return {'type': 'ir.actions.act_window_close'}
statement = statement_obj.browse(cr, uid, context['active_id'], context=context) statement = statement_obj.browse(
cr, uid, context['active_id'], context=context)
for line in line_obj.browse(cr, uid, line_ids, context=context): for line in line_obj.browse(cr, uid, line_ids, context=context):
ctx = context.copy() ctx = context.copy()
ctx['date'] = line.ml_maturity_date # Last value_date earlier,but this field exists no more now # Last value_date earlier,but this field exists no more now
ctx['date'] = line.ml_maturity_date
amount = currency_obj.compute(cr, uid, line.currency.id, amount = currency_obj.compute(cr, uid, line.currency.id,
statement.currency.id, line.amount_currency, context=ctx) statement.currency.id, line.amount_currency, context=ctx)
if not line.move_line_id.id: if not line.move_line_id.id:
@@ -124,7 +127,8 @@ class AccountPaymentPopulateStatement(orm.TransientModel):
st_line_id = statement_line_obj.create(cr, uid, vals, st_line_id = statement_line_obj.create(cr, uid, vals,
context=context) context=context)
line_obj.write(cr, uid, [line.id], {'bank_statement_line_id': st_line_id}) line_obj.write(
cr, uid, [line.id], {'bank_statement_line_id': st_line_id})
return {'type': 'ir.actions.act_window_close'} return {'type': 'ir.actions.act_window_close'}
def _prepare_statement_line_vals(self, cr, uid, payment_line, amount, def _prepare_statement_line_vals(self, cr, uid, payment_line, amount,