mirror of
https://github.com/OCA/account-reconcile.git
synced 2025-01-20 12:27:39 +02:00
[ENH] Began extracting the commission-handling feature from account_statement_base_import.
The extracted commission part is not functional, but the base_import module still works.
This commit is contained in:
@@ -28,37 +28,41 @@ try:
|
||||
except:
|
||||
raise Exception(_('Please install python lib xlrd'))
|
||||
|
||||
def float_or_zero(val):
|
||||
""" Conversion function used to manage
|
||||
empty string into float usecase"""
|
||||
return float(val) if val else 0.0
|
||||
|
||||
class FileParser(BankStatementImportParser):
|
||||
"""
|
||||
Generic abstract class for defining parser for .csv or .xls file format.
|
||||
"""
|
||||
|
||||
def __init__(self, parse_name, keys_to_validate=None, ftype='csv', conversion_dict=None,
|
||||
header=None, *args, **kwargs):
|
||||
def __init__(self, parse_name, ftype='csv', extra_fields=None, header=None, **kwargs):
|
||||
"""
|
||||
:param char: parse_name : The name of the parser
|
||||
:param list: keys_to_validate : contain the key that need to be present in the file
|
||||
:param char ftype: extension of the file (could be csv or xls)
|
||||
:param: conversion_dict : keys and type to convert of every column in the file like
|
||||
{
|
||||
'ref': unicode,
|
||||
'label': unicode,
|
||||
'date': datetime.datetime,
|
||||
'amount': float,
|
||||
'commission_amount': float
|
||||
}
|
||||
:param dict extra_fields: extra fields to add to the conversion dict. In the format
|
||||
{fieldname: fieldtype}
|
||||
:param list: header : specify header fields if the csv file has no header
|
||||
"""
|
||||
|
||||
super(FileParser, self).__init__(parse_name, *args, **kwargs)
|
||||
super(FileParser, self).__init__(parse_name, **kwargs)
|
||||
if ftype in ('csv', 'xls'):
|
||||
self.ftype = ftype
|
||||
else:
|
||||
raise except_osv(_('User Error'),
|
||||
_('Invalid file type %s. Please use csv or xls') % ftype)
|
||||
self.keys_to_validate = keys_to_validate if keys_to_validate is not None else []
|
||||
self.conversion_dict = conversion_dict
|
||||
self.conversion_dict = {
|
||||
'ref': unicode,
|
||||
'label': unicode,
|
||||
'date': datetime.datetime,
|
||||
'amount': float_or_zero,
|
||||
}
|
||||
if extra_fields:
|
||||
self.conversion_dict.update(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).
|
||||
|
||||
@@ -30,12 +30,6 @@ except:
|
||||
raise Exception(_('Please install python lib xlrd'))
|
||||
|
||||
|
||||
def float_or_zero(val):
|
||||
""" Conversion function used to manage
|
||||
empty string into float usecase"""
|
||||
return float(val) if val else 0.0
|
||||
|
||||
|
||||
class GenericFileParser(FileParser):
|
||||
"""
|
||||
Standard parser that use a define format in csv or xls to import into a
|
||||
@@ -43,17 +37,8 @@ class GenericFileParser(FileParser):
|
||||
parser, but will also be useful as it allow to import a basic flat file.
|
||||
"""
|
||||
|
||||
def __init__(self, parse_name, ftype='csv'):
|
||||
conversion_dict = {
|
||||
'ref': unicode,
|
||||
'label': unicode,
|
||||
'date': datetime.datetime,
|
||||
'amount': float_or_zero,
|
||||
'commission_amount': float_or_zero
|
||||
}
|
||||
# Order of cols does not matter but first row of the file has to be header
|
||||
keys_to_validate = ['ref', 'label', 'date', 'amount', 'commission_amount']
|
||||
super(GenericFileParser, self).__init__(parse_name, keys_to_validate=keys_to_validate, ftype=ftype, conversion_dict=conversion_dict)
|
||||
def __init__(self, parse_name, ftype='csv', **kwargs):
|
||||
super(GenericFileParser, self).__init__(parse_name, ftype=ftype, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def parser_for(cls, parser_name):
|
||||
@@ -78,25 +63,12 @@ class GenericFileParser(FileParser):
|
||||
'amount':value,
|
||||
'ref':value,
|
||||
'label':value,
|
||||
'commission_amount':value,
|
||||
}
|
||||
In this generic parser, the commission is given for every line, so we store it
|
||||
for each one.
|
||||
"""
|
||||
return {'name': line.get('label', line.get('ref', '/')),
|
||||
return {
|
||||
'name': line.get('label', line.get('ref', '/')),
|
||||
'date': line.get('date', datetime.datetime.now().date()),
|
||||
'amount': line.get('amount', 0.0),
|
||||
'ref': line.get('ref', '/'),
|
||||
'label': line.get('label', ''),
|
||||
'commission_amount': line.get('commission_amount', 0.0)}
|
||||
|
||||
def _post(self, *args, **kwargs):
|
||||
"""
|
||||
Compute the commission from value of each line
|
||||
"""
|
||||
res = super(GenericFileParser, self)._post(*args, **kwargs)
|
||||
val = 0.0
|
||||
for row in self.result_row_list:
|
||||
val += row.get('commission_amount', 0.0)
|
||||
self.commission_global_amount = val
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -49,9 +49,6 @@ class BankStatementImportParser(object):
|
||||
self.result_row_list = None
|
||||
# The file buffer on which to work on
|
||||
self.filebuffer = None
|
||||
# Concatenate here the global commission taken by the bank/office
|
||||
# for this statement.
|
||||
self.commission_global_amount = None
|
||||
|
||||
@classmethod
|
||||
def parser_for(cls, parser_name):
|
||||
@@ -110,8 +107,6 @@ class BankStatementImportParser(object):
|
||||
"""
|
||||
Implement a method in your parser to make some last changes on the result of parsing
|
||||
the datas, like converting dates, computing commission, ...
|
||||
Work on self.result_row_list and put the commission global amount if any
|
||||
in the self.commission_global_amount one.
|
||||
"""
|
||||
return NotImplementedError
|
||||
|
||||
@@ -133,16 +128,6 @@ class BankStatementImportParser(object):
|
||||
"""
|
||||
return NotImplementedError
|
||||
|
||||
def get_st_line_commision(self, *args, **kwargs):
|
||||
"""
|
||||
This is called by the importation method to create the commission line in
|
||||
the bank statement. We will always create one line for the commission in the
|
||||
bank statement, but it could be computated from a value of each line, or given
|
||||
in a single line for the whole file.
|
||||
return: float of the whole commission (self.commission_global_amount)
|
||||
"""
|
||||
return self.commission_global_amount
|
||||
|
||||
def parse(self, filebuffer, *args, **kwargs):
|
||||
"""
|
||||
This will be the method that will be called by wizard, button and so
|
||||
|
||||
@@ -56,6 +56,21 @@ class AccountStatementProfil(Model):
|
||||
|
||||
}
|
||||
|
||||
def _write_extra_statement_lines(
|
||||
self, cr, uid, parser, result_row_list, profile, statement_id, context):
|
||||
"""Insert extra lines after the main statement lines.
|
||||
|
||||
After the main statement lines have been created, you can override this method to create
|
||||
extra statement lines.
|
||||
|
||||
:param: browse_record of the current parser
|
||||
:param: result_row_list: [{'key':value}]
|
||||
:param: profile: browserecord of account.statement.profile
|
||||
:param: statement_id: int/long of the current importing 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
|
||||
@@ -72,41 +87,6 @@ class AccountStatementProfil(Model):
|
||||
context=context)
|
||||
return True
|
||||
|
||||
def prepare_global_commission_line_vals(
|
||||
self, cr, uid, parser, result_row_list, profile, statement_id, context):
|
||||
"""
|
||||
Prepare the global commission line if there is one. The global
|
||||
commission is computed by by calling the get_st_line_commision
|
||||
of the parser. Feel free to override the method to compute
|
||||
your own commission line from the result_row_list.
|
||||
|
||||
:param: browse_record of the current parser
|
||||
:param: result_row_list: [{'key':value}]
|
||||
:param: profile: browserecord of account.statement.profile
|
||||
:param: statement_id: int/long of the current importing statement ID
|
||||
:param: context: global context
|
||||
return: dict of vals that will be passed to create method of statement line.
|
||||
"""
|
||||
comm_values = False
|
||||
if parser.get_st_line_commision():
|
||||
partner_id = profile.partner_id and profile.partner_id.id or False
|
||||
commission_account_id = profile.commission_account_id and profile.commission_account_id.id or False
|
||||
commission_analytic_id = profile.commission_analytic_id and profile.commission_analytic_id.id or False
|
||||
comm_values = {
|
||||
'name': 'IN ' + _('Commission line'),
|
||||
'date': datetime.datetime.now().date(),
|
||||
'amount': parser.get_st_line_commision(),
|
||||
'partner_id': partner_id,
|
||||
'type': 'general',
|
||||
'statement_id': statement_id,
|
||||
'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!
|
||||
'already_completed': True,
|
||||
}
|
||||
return comm_values
|
||||
|
||||
def prepare_statetement_lines_vals(
|
||||
self, cr, uid, parser_vals, account_payable, account_receivable,
|
||||
statement_id, context):
|
||||
@@ -153,8 +133,6 @@ class AccountStatementProfil(Model):
|
||||
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.
|
||||
It will also create the commission line if it apply and record the providen file as
|
||||
an attachement of the bank statement.
|
||||
|
||||
:param int/long profile_id: ID of the profile used to import the file
|
||||
:param filebuffer file_stream: binary of the providen file
|
||||
@@ -192,41 +170,33 @@ class AccountStatementProfil(Model):
|
||||
account_receivable, account_payable = statement_obj.get_default_pay_receiv_accounts(
|
||||
cr, uid, context)
|
||||
try:
|
||||
# Record every line in the bank statement and compute the global commission
|
||||
# based on the commission_amount column
|
||||
# Record every line in the bank statement
|
||||
statement_store = []
|
||||
for line in result_row_list:
|
||||
parser_vals = parser.get_st_line_vals(line)
|
||||
values = self.prepare_statetement_lines_vals(cr, uid, parser_vals, account_payable,
|
||||
account_receivable, statement_id, context)
|
||||
values = self.prepare_statetement_lines_vals(
|
||||
cr, uid, parser_vals, account_payable, account_receivable, statement_id,
|
||||
context)
|
||||
statement_store.append(values)
|
||||
# Hack to bypass ORM poor perfomance. Sob...
|
||||
statement_line_obj._insert_lines(cr, uid, statement_store, context=context)
|
||||
|
||||
# Build and create the global commission line for the whole statement
|
||||
comm_vals = self.prepare_global_commission_line_vals(cr, uid, parser, result_row_list,
|
||||
prof, statement_id, context)
|
||||
if comm_vals:
|
||||
statement_line_obj.create(cr, uid, comm_vals, context=context)
|
||||
else:
|
||||
self._write_extra_statement_lines(
|
||||
cr, uid, parser, result_row_list, prof, statement_id, context)
|
||||
# Trigger store field computation if someone has better idea
|
||||
start_bal = statement_obj.read(cr, uid, statement_id,
|
||||
['balance_start'],
|
||||
context=context)
|
||||
start_bal = statement_obj.read(
|
||||
cr, uid, statement_id, ['balance_start'], context=context)
|
||||
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_obj.create(cr,
|
||||
uid,
|
||||
{'name': 'statement file',
|
||||
attachment_data = {
|
||||
'name': 'statement file',
|
||||
'datas': file_stream,
|
||||
'datas_fname': "%s.%s" % (
|
||||
datetime.datetime.now().date(),
|
||||
ftype),
|
||||
'datas_fname': "%s.%s" % (datetime.datetime.now().date(), ftype),
|
||||
'res_model': 'account.bank.statement',
|
||||
'res_id': statement_id},
|
||||
context=context)
|
||||
'res_id': statement_id,
|
||||
}
|
||||
attachment_obj.create(cr, uid, attachment_data, context=context)
|
||||
|
||||
# If user ask to launch completion at end of import, do it!
|
||||
if prof.launch_import_completion:
|
||||
@@ -251,8 +221,7 @@ class AccountStatementProfil(Model):
|
||||
class AccountStatementLine(Model):
|
||||
"""
|
||||
Add sparse field on the statement line to allow to store all the
|
||||
bank infos that are given by an office. In this basic sample case
|
||||
it concern only commission_amount.
|
||||
bank infos that are given by an office.
|
||||
"""
|
||||
_inherit = "account.bank.statement.line"
|
||||
|
||||
@@ -294,10 +263,3 @@ class AccountStatementLine(Model):
|
||||
cr.rollback()
|
||||
raise osv.except_osv(_("ORM bypass error"),
|
||||
sql_err.pgerror)
|
||||
|
||||
_columns = {
|
||||
'commission_amount': fields.sparse(
|
||||
type='float',
|
||||
string='Line Commission Amount',
|
||||
serialization_field='additionnal_bank_fields'),
|
||||
}
|
||||
|
||||
44
account_statement_commission/commission.py
Normal file
44
account_statement_commission/commission.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from openerp.tools.translate import _
|
||||
import datetime
|
||||
from openerp.osv import fields
|
||||
from openerp.osv.orm import Model
|
||||
|
||||
class AccountStatementProfil(Model):
|
||||
_inherit = "account.statement.profile"
|
||||
|
||||
def _write_extra_statement_lines(
|
||||
self, cr, uid, parser, result_row_list, profile, statement_id, context):
|
||||
"""Prepare the global commission line if there is one.
|
||||
"""
|
||||
global_commission_amount = 0
|
||||
for row in parser.result_row_list:
|
||||
global_commission_amount += row.get('commission_amount', 0.0)
|
||||
if not global_commission_amount:
|
||||
return
|
||||
partner_id = profile.partner_id and profile.partner_id.id or False
|
||||
commission_account_id = profile.commission_account_id and profile.commission_account_id.id or False
|
||||
commission_analytic_id = profile.commission_analytic_id and profile.commission_analytic_id.id or False
|
||||
comm_values = {
|
||||
'name': 'IN ' + _('Commission line'),
|
||||
'date': datetime.datetime.now().date(),
|
||||
'amount': global_commission_amount,
|
||||
'partner_id': partner_id,
|
||||
'type': 'general',
|
||||
'statement_id': statement_id,
|
||||
'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!
|
||||
'already_completed': True,
|
||||
}
|
||||
statement_line_obj = self.pool.get('account.bank.statement.line')
|
||||
statement_line_obj.create(cr, uid, comm_values, context=context)
|
||||
|
||||
class AccountStatementLineWithCommission(Model):
|
||||
_inherit = "account.bank.statement.line"
|
||||
_columns = {
|
||||
'commission_amount': fields.sparse(
|
||||
type='float',
|
||||
string='Line Commission Amount',
|
||||
serialization_field='additionnal_bank_fields'),
|
||||
}
|
||||
Reference in New Issue
Block a user