[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:
Virgil Dupras
2013-05-03 15:57:26 -04:00
parent 6500ac2765
commit 35507cd40c
5 changed files with 105 additions and 138 deletions

View File

@@ -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).

View File

@@ -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
}

View File

@@ -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

View File

@@ -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'),
}

View 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'),
}