diff --git a/account_statement_base_import/parser/file_parser.py b/account_statement_base_import/parser/file_parser.py index 938863a3..54f7a4bb 100644 --- a/account_statement_base_import/parser/file_parser.py +++ b/account_statement_base_import/parser/file_parser.py @@ -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). diff --git a/account_statement_base_import/parser/generic_file_parser.py b/account_statement_base_import/parser/generic_file_parser.py index 7d04bfab..81e51c8c 100644 --- a/account_statement_base_import/parser/generic_file_parser.py +++ b/account_statement_base_import/parser/generic_file_parser.py @@ -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', '/')), - '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 + 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', ''), + } diff --git a/account_statement_base_import/parser/parser.py b/account_statement_base_import/parser/parser.py index 6d6d0c25..377548b2 100644 --- a/account_statement_base_import/parser/parser.py +++ b/account_statement_base_import/parser/parser.py @@ -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 diff --git a/account_statement_base_import/statement.py b/account_statement_base_import/statement.py index 69b725f2..3b7998cc 100644 --- a/account_statement_base_import/statement.py +++ b/account_statement_base_import/statement.py @@ -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: - # Trigger store field computation if someone has better idea - 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}) + 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 = start_bal['balance_start'] + statement_obj.write(cr, uid, [statement_id], {'balance_start': start_bal}) - attachment_obj.create(cr, - uid, - {'name': 'statement file', - 'datas': file_stream, - 'datas_fname': "%s.%s" % ( - datetime.datetime.now().date(), - ftype), - 'res_model': 'account.bank.statement', - 'res_id': statement_id}, - context=context) + attachment_data = { + 'name': 'statement file', + 'datas': file_stream, + 'datas_fname': "%s.%s" % (datetime.datetime.now().date(), ftype), + 'res_model': 'account.bank.statement', + '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'), - } diff --git a/account_statement_commission/commission.py b/account_statement_commission/commission.py new file mode 100644 index 00000000..ce928b41 --- /dev/null +++ b/account_statement_commission/commission.py @@ -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'), + }