diff --git a/account_move_base_import/models/account_journal.py b/account_move_base_import/models/account_journal.py index e6eabd01..6b9a3658 100644 --- a/account_move_base_import/models/account_journal.py +++ b/account_move_base_import/models/account_journal.py @@ -12,63 +12,67 @@ from odoo.exceptions import UserError, ValidationError class AccountJournal(models.Model): - _name = 'account.journal' - _inherit = ['account.journal', 'mail.thread'] - _order = 'sequence' + _name = "account.journal" + _inherit = ["account.journal", "mail.thread"] + _order = "sequence" - used_for_import = fields.Boolean( - string="Journal used for import") + used_for_import = fields.Boolean(string="Journal used for import") commission_account_id = fields.Many2one( - comodel_name='account.account', - string='Commission account') + comodel_name="account.account", string="Commission account" + ) import_type = fields.Selection( - [('generic_csvxls_so', 'Generic .csv/.xls based on SO Name')], - string='Type of import', - default='generic_csvxls_so', + [("generic_csvxls_so", "Generic .csv/.xls based on SO Name")], + string="Type of import", + default="generic_csvxls_so", required=True, help="Choose here the method by which you want to import account " - "moves for this journal.") + "moves for this journal.", + ) - last_import_date = fields.Datetime( - string="Last Import Date") + last_import_date = fields.Datetime(string="Last Import Date") partner_id = fields.Many2one( - comodel_name='res.partner', - string='Bank/Payment Office partner', + comodel_name="res.partner", + string="Bank/Payment Office partner", help="Put a partner if you want to have it on the commission move " "(and optionaly on the counterpart of the intermediate/" - "banking move if you tick the corresponding checkbox).") + "banking move if you tick the corresponding checkbox).", + ) receivable_account_id = fields.Many2one( - comodel_name='account.account', - string='Receivable/Payable Account', + comodel_name="account.account", + string="Receivable/Payable Account", help="Choose a receivable/payable account to use as the default " - "debit/credit account.") + "debit/credit account.", + ) - used_for_completion = fields.Boolean( - string="Journal used for completion") + used_for_completion = fields.Boolean(string="Journal used for completion") rule_ids = fields.Many2many( - comodel_name='account.move.completion.rule', - string='Auto-completion rules', - relation='account_journal_completion_rule_rel') + comodel_name="account.move.completion.rule", + string="Auto-completion rules", + relation="account_journal_completion_rule_rel", + ) launch_import_completion = fields.Boolean( string="Launch completion after import", help="Tic that box to automatically launch the completion " - "on each imported file using this journal.") + "on each imported file using this journal.", + ) create_counterpart = fields.Boolean( string="Create Counterpart", help="Tick that box to automatically create the move counterpart", - default=True) + default=True, + ) split_counterpart = fields.Boolean( string="Split Counterpart", help="Two counterparts will be automatically created : one for " - "the refunds and one for the payments") + "the refunds and one for the payments", + ) @api.multi def _prepare_counterpart_line(self, move, amount, date): @@ -81,24 +85,24 @@ class AccountJournal(models.Model): credit = -amount debit = 0.0 counterpart_values = { - 'date_maturity': date, - 'credit': credit, - 'debit': debit, - 'partner_id': self.partner_id.id, - 'move_id': move.id, - 'account_id': account_id, - 'already_completed': True, - 'journal_id': self.id, - 'company_id': self.company_id.id, - 'currency_id': self.currency_id.id, - 'company_currency_id': self.company_id.currency_id.id, - 'amount_residual': amount, + "date_maturity": date, + "credit": credit, + "debit": debit, + "partner_id": self.partner_id.id, + "move_id": move.id, + "account_id": account_id, + "already_completed": True, + "journal_id": self.id, + "company_id": self.company_id.id, + "currency_id": self.currency_id.id, + "company_currency_id": self.company_id.currency_id.id, + "amount_residual": amount, } return counterpart_values @api.multi def _create_counterpart(self, parser, move): - move_line_obj = self.env['account.move.line'] + move_line_obj = self.env["account.move.line"] refund = 0.0 payment = 0.0 transfer_lines = [] @@ -114,16 +118,18 @@ class AccountJournal(models.Model): total_amount = refund + payment if total_amount: transfer_lines.append(total_amount) - counterpart_date = parser.get_move_vals().get('date') or \ - fields.Date.today() + counterpart_date = ( + parser.get_move_vals().get("date") or fields.Date.today() + ) transfer_line_count = len(transfer_lines) check_move_validity = False for amount in transfer_lines: transfer_line_count -= 1 if not transfer_line_count: check_move_validity = True - vals = self._prepare_counterpart_line(move, amount, - counterpart_date) + vals = self._prepare_counterpart_line( + move, amount, counterpart_date + ) move_line_obj.with_context( check_move_validity=check_move_validity ).create(vals) @@ -142,48 +148,53 @@ class AccountJournal(models.Model): statement ID :param: context: global context """ - move_line_obj = self.env['account.move.line'] + move_line_obj = self.env["account.move.line"] global_commission_amount = 0 for row in parser.result_row_list: global_commission_amount += float( - row.get('commission_amount', '0.0')) + row.get("commission_amount", "0.0") + ) partner_id = self.partner_id.id # Commission line if global_commission_amount > 0.0: - raise UserError(_('Commission amount should not be positive.')) + raise UserError(_("Commission amount should not be positive.")) elif global_commission_amount < 0.0: if not self.commission_account_id: raise UserError( - _('No commission account is set on the journal.')) + _("No commission account is set on the journal.") + ) else: commission_account_id = self.commission_account_id.id comm_values = { - 'name': _('Commission line'), - 'date_maturity': parser.get_move_vals().get('date') or - fields.Date.today(), - 'debit': -global_commission_amount, - 'partner_id': partner_id, - 'move_id': move.id, - 'account_id': commission_account_id, - 'already_completed': True, + "name": _("Commission line"), + "date_maturity": ( + parser.get_move_vals().get("date") + or fields.Date.today() + ), + "debit": -global_commission_amount, + "partner_id": partner_id, + "move_id": move.id, + "account_id": commission_account_id, + "already_completed": True, } - if (self.currency_id and - self.currency_id != self.company_id.currency_id): + if ( + self.currency_id + and self.currency_id != self.company_id.currency_id + ): # the commission we are reading is in the currency of the # journal: use the amount in the amount_currency field, and # set credit / debit to the value in company currency at # the date of the move. currency = self.currency_id.with_context(date=move.date) company_currency = self.company_id.currency_id - comm_values['amount_currency'] = comm_values['debit'] - comm_values['debit'] = currency.compute( - comm_values['debit'], - company_currency + comm_values["amount_currency"] = comm_values["debit"] + comm_values["debit"] = currency.compute( + comm_values["debit"], company_currency ) - comm_values['currency_id'] = currency.id - move_line_obj.with_context( - check_move_validity=False - ).create(comm_values) + comm_values["currency_id"] = currency.id + move_line_obj.with_context(check_move_validity=False).create( + comm_values + ) @api.multi def write_logs_after_import(self, move, num_lines): @@ -195,8 +206,9 @@ class AccountJournal(models.Model): :return: True """ self.message_post( - body=_('Move %s have been imported with %s ' - 'lines.') % (move.name, num_lines)) + body=_("Move %s have been imported with %s " "lines.") + % (move.name, num_lines) + ) return True def prepare_move_line_vals(self, parser_vals, move): @@ -211,44 +223,46 @@ class AccountJournal(models.Model): :return: dict of vals that will be passed to create method of statement line. """ - move_line_obj = self.env['account.move.line'] + move_line_obj = self.env["account.move.line"] values = parser_vals - if not values.get('account_id', False): - values['account_id'] = self.receivable_account_id.id - account = self.env['account.account'].browse(values['account_id']) - if (self.currency_id and - self.currency_id != self.company_id.currency_id): + if not values.get("account_id", False): + values["account_id"] = self.receivable_account_id.id + account = self.env["account.account"].browse(values["account_id"]) + if ( + self.currency_id + and self.currency_id != self.company_id.currency_id + ): # the debit and credit we are reading are in the currency of the # journal: use the amount in the amount_currency field, and set # credit / debit to the value in company currency at the date of # the move. currency = self.currency_id.with_context(date=move.date) company_currency = self.company_id.currency_id - values['amount_currency'] = values['debit'] - values['credit'] - values['debit'] = currency.compute(values['debit'], - company_currency) - values['credit'] = currency.compute(values['credit'], - company_currency) + values["amount_currency"] = values["debit"] - values["credit"] + values["debit"] = currency.compute( + values["debit"], company_currency + ) + values["credit"] = currency.compute( + values["credit"], company_currency + ) if account.reconcile: - values['amount_residual'] = values['debit'] - values['credit'] + values["amount_residual"] = values["debit"] - values["credit"] else: - values['amount_residual'] = 0 - values.update({ - 'company_id': self.company_id.id, - 'currency_id': self.currency_id.id, - 'company_currency_id': self.company_id.currency_id.id, - 'journal_id': self.id, - 'move_id': move.id, - 'date': move.date, - 'balance': values['debit'] - values['credit'], - 'amount_residual_currency': 0, - 'debit_cash_basic': values['debit'], - 'credit_cash_basic': values['credit'], - 'balance_cash_basic': values['debit'] - values['credit'], - 'ref': move.ref, - 'user_type_id': account.user_type_id.id, - 'reconciled': False, - }) + values["amount_residual"] = 0 + values.update( + { + "company_id": self.company_id.id, + "currency_id": self.currency_id.id, + "company_currency_id": self.company_id.currency_id.id, + "journal_id": self.id, + "move_id": move.id, + "date": move.date, + "balance": values["debit"] - values["credit"], + "amount_residual_currency": 0, + "user_type_id": account.user_type_id.id, + "reconciled": False, + } + ) values = move_line_obj._add_missing_default_values(values) return values @@ -256,9 +270,11 @@ class AccountJournal(models.Model): """Hook to build the values of the statement from the parser and the profile. """ - vals = {'journal_id': self.id, - 'currency_id': self.currency_id.id, - 'import_partner_id': self.partner_id.id} + vals = { + "journal_id": self.id, + "currency_id": self.currency_id.id, + "import_partner_id": self.partner_id.id, + } vals.update(parser.get_move_vals()) return vals @@ -271,17 +287,23 @@ class AccountJournal(models.Model): :param char: ftype represent the file extension (csv by default) :return: list: list of ids of the created account.bank.statement """ - filename = self._context.get('file_name', None) + filename = self._context.get("file_name", None) if filename: (filename, __) = os.path.splitext(filename) parser = new_move_parser(self, ftype=ftype, move_ref=filename) - res = self.env['account.move'] + res = self.env["account.move"] for result_row_list in parser.parse(file_stream): - move = self._move_import(parser, file_stream, ftype=ftype) + move = self._move_import( + parser, + file_stream, + result_row_list=result_row_list, + ftype=ftype, + ) res |= move return res - def _move_import(self, parser, file_stream, ftype="csv"): + def _move_import( + self, parser, file_stream, result_row_list=None, ftype="csv"): """Create a bank statement with the given profile and parser. It will fulfill the bank statement with the values of the file provided, but will not complete data (like finding the partner, or the right @@ -293,22 +315,26 @@ class AccountJournal(models.Model): :param char: ftype represent the file extension (csv by default) :return: ID of the created account.bank.statement """ - move_obj = self.env['account.move'] - move_line_obj = self.env['account.move.line'] - attachment_obj = self.env['ir.attachment'] - result_row_list = parser.result_row_list + move_obj = self.env["account.move"] + move_line_obj = self.env["account.move.line"] + attachment_obj = self.env["ir.attachment"] + if result_row_list is None: + result_row_list = parser.result_row_list # Check all key are present in account.bank.statement.line!! if not result_row_list: - raise UserError(_("Nothing to import: " - "The file is empty")) + raise UserError(_("Nothing to import: " "The file is empty")) parsed_cols = list( parser.get_move_line_vals(result_row_list[0]).keys() ) for col in parsed_cols: if col not in move_line_obj._fields: raise UserError( - _("Missing column! Column %s you try to import is not " - "present in the move line!") % col) + _( + "Missing column! Column %s you try to import is not " + "present in the move line!" + ) + % col + ) move_vals = self.prepare_move_vals(result_row_list, parser) move = move_obj.create(move_vals) try: @@ -330,11 +356,11 @@ class AccountJournal(models.Model): move._amount_compute() # Attach data to the move attachment_data = { - 'name': 'statement file', - 'datas': file_stream, - 'datas_fname': "%s.%s" % (fields.Date.today(), ftype), - 'res_model': 'account.move', - 'res_id': move.id, + "name": "statement file", + "datas": file_stream, + "datas_fname": "%s.%s" % (fields.Date.today(), ftype), + "res_model": "account.move", + "res_id": move.id, } attachment_obj.create(attachment_data) # If user ask to launch completion at end of import, do it! @@ -348,9 +374,15 @@ class AccountJournal(models.Model): except Exception: error_type, error_value, trbk = sys.exc_info() st = "Error: %s\nDescription: %s\nTraceback:" % ( - error_type.__name__, error_value) - st += ''.join(traceback.format_tb(trbk, 30)) + error_type.__name__, + error_value, + ) + st += "".join(traceback.format_tb(trbk, 30)) raise ValidationError( - _("Statement import error " - "The statement cannot be created: %s") % st) + _( + "Statement import error " + "The statement cannot be created: %s" + ) + % st + ) return move diff --git a/account_move_base_import/parser/file_parser.py b/account_move_base_import/parser/file_parser.py index 8893b96b..9cc048d8 100644 --- a/account_move_base_import/parser/file_parser.py +++ b/account_move_base_import/parser/file_parser.py @@ -32,8 +32,15 @@ class FileParser(AccountMoveImportParser): format. """ - def __init__(self, journal, ftype='csv', extra_fields=None, header=None, - dialect=None, move_ref=None, **kwargs): + def __init__( + self, + journal, + ftype="csv", + extra_fields=None, + header=None, + dialect=None, + move_ref=None, + **kwargs): """ :param char: parse_name: The name of the parser :param char: ftype: extension of the file (could be csv, xls or @@ -44,11 +51,12 @@ class FileParser(AccountMoveImportParser): header """ super().__init__(journal, **kwargs) - if ftype in ('csv', 'xls', 'xlsx'): + if ftype in ("csv", "xls", "xlsx"): self.ftype = ftype[0:3] else: raise UserError( - _('Invalid file type %s. Please use csv, xls or xlsx') % ftype) + _("Invalid file type %s. Please use csv, xls or xlsx") % ftype + ) self.conversion_dict = extra_fields self.keys_to_validate = list(self.conversion_dict.keys()) self.fieldnames = header @@ -57,6 +65,8 @@ class FileParser(AccountMoveImportParser): # Set in _parse_xls, from the contents of the file self.dialect = dialect self.move_ref = move_ref + self.parsed_file = None + self.current_line = 0 def _custom_format(self, *args, **kwargs): """No other work on data are needed in this parser.""" @@ -70,13 +80,23 @@ class FileParser(AccountMoveImportParser): """Launch the parsing through .csv, .xls or .xlsx depending on the given ftype """ - res = None - if self.ftype == 'csv': - res = self._parse_csv() + if self.parsed_file is None: + if self.ftype == "csv": + self.parsed_file = self._parse_csv() + else: + self.parsed_file = self._parse_xls() + if self.support_multi_moves: + if len(self.parsed_file) <= self.current_line: + return False + else: + self.result_row_list = self.parsed_file[ + self.current_line: self.current_line + 1 + ] + self.current_line += 1 + return True else: - res = self._parse_xls() - self.result_row_list = res - return True + self.result_row_list = self.parsed_file + return True def _validate(self, *args, **kwargs): """We check that all the key of the given file (means header) are @@ -88,7 +108,7 @@ class FileParser(AccountMoveImportParser): parsed_cols = list(self.result_row_list[0].keys()) for col in self.keys_to_validate: if col not in parsed_cols: - raise UserError(_('Column %s not present in file') % col) + raise UserError(_("Column %s not present in file") % col) return True def _post(self, *args, **kwargs): @@ -102,9 +122,10 @@ class FileParser(AccountMoveImportParser): csv_file = tempfile.NamedTemporaryFile() csv_file.write(self.filebuffer) csv_file.flush() - with open(csv_file.name, 'rU') as fobj: - reader = UnicodeDictReader(fobj, fieldnames=self.fieldnames, - dialect=self.dialect) + with open(csv_file.name, "rU") as fobj: + reader = UnicodeDictReader( + fobj, fieldnames=self.fieldnames, dialect=self.dialect + ) return list(reader) def _parse_xls(self): @@ -130,26 +151,41 @@ class FileParser(AccountMoveImportParser): for rule in conversion_rules: if conversion_rules[rule] == datetime.datetime: try: - date_string = line[rule].split(' ')[0] - line[rule] = datetime.datetime.strptime(date_string, - '%Y-%m-%d') + date_string = line[rule].split(" ")[0] + line[rule] = datetime.datetime.strptime( + date_string, "%Y-%m-%d" + ) except ValueError as err: raise UserError( - _("Date format is not valid." - " It should be YYYY-MM-DD for column: %s" - " value: %s \n \n \n Please check the line with " - "ref: %s \n \n Detail: %s") % - (rule, line.get(rule, _('Missing')), - line.get('ref', line), repr(err))) + _( + "Date format is not valid." + " It should be YYYY-MM-DD for column: %s" + " value: %s \n \n \n Please check" + " the line with ref: %s \n \n Detail: %s" + ) + % ( + rule, + line.get(rule, _("Missing")), + line.get("ref", line), + repr(err), + ) + ) else: try: line[rule] = conversion_rules[rule](line[rule]) except Exception as err: raise UserError( - _("Value %s of column %s is not valid.\n Please " - "check the line with ref %s:\n \n Detail: %s") % - (line.get(rule, _('Missing')), rule, - line.get('ref', line), repr(err))) + _( + "Value %s of column %s is not valid.\n Please " + "check the line with ref %s:\n \n Detail: %s" + ) + % ( + line.get(rule, _("Missing")), + rule, + line.get("ref", line), + repr(err), + ) + ) return result_set def _from_xls(self, result_set, conversion_rules): @@ -160,26 +196,41 @@ class FileParser(AccountMoveImportParser): for rule in conversion_rules: if conversion_rules[rule] == datetime.datetime: 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) except Exception as err: raise UserError( - _("Date format is not valid. " - "Please modify the cell formatting to date " - "format for column: %s value: %s\n Please check " - "the line with ref: %s\n \n Detail: %s") % - (rule, line.get(rule, _('Missing')), - line.get('ref', line), repr(err))) + _( + "Date format is not valid. " + "Please modify the cell formatting to date " + "format for column: %s value: %s\n Please" + " check the line with ref: %s\n \n Detail: %s" + ) + % ( + rule, + line.get(rule, _("Missing")), + line.get("ref", line), + repr(err), + ) + ) else: try: line[rule] = conversion_rules[rule](line[rule]) except Exception as err: raise UserError( - _("Value %s of column %s is not valid.\n Please " - "check the line with ref %s:\n \n Detail: %s") % - (line.get(rule, _('Missing')), rule, - line.get('ref', line), repr(err))) + _( + "Value %s of column %s is not valid.\n Please " + "check the line with ref %s:\n \n Detail: %s" + ) + % ( + line.get(rule, _("Missing")), + rule, + line.get("ref", line), + repr(err), + ) + ) return result_set def _cast_rows(self, *args, **kwargs): @@ -187,6 +238,6 @@ class FileParser(AccountMoveImportParser): providen. We call here _from_xls or _from_csv depending on the self.ftype variable. """ - func = getattr(self, '_from_%s' % self.ftype) + func = getattr(self, "_from_%s" % self.ftype) res = func(self.result_row_list, self.conversion_dict) return res diff --git a/account_move_base_import/demo/statement.csv b/account_move_base_import/tests/data/statement.csv similarity index 100% rename from account_move_base_import/demo/statement.csv rename to account_move_base_import/tests/data/statement.csv diff --git a/account_move_base_import/demo/statement.xls b/account_move_base_import/tests/data/statement.xls similarity index 100% rename from account_move_base_import/demo/statement.xls rename to account_move_base_import/tests/data/statement.xls diff --git a/account_move_base_import/tests/test_base_import.py b/account_move_base_import/tests/test_base_import.py index 7eaf1609..57781ca2 100644 --- a/account_move_base_import/tests/test_base_import.py +++ b/account_move_base_import/tests/test_base_import.py @@ -53,7 +53,10 @@ class TestCodaImport(common.TransactionCase): """Test import from xls """ file_name = get_resource_path( - 'account_move_base_import', 'demo', 'statement.xls' + 'account_move_base_import', + 'tests', + 'data', + 'statement.xls' ) move = self._import_file(file_name) self._validate_imported_move(move) @@ -62,7 +65,10 @@ class TestCodaImport(common.TransactionCase): """Test import from csv """ file_name = get_resource_path( - 'account_move_base_import', 'demo', 'statement.csv' + 'account_move_base_import', + 'tests', + 'data', + 'statement.csv' ) move = self._import_file(file_name) self._validate_imported_move(move) diff --git a/account_move_transactionid_import/parser/transactionid_file_parser.py b/account_move_transactionid_import/parser/transactionid_file_parser.py index e57b4366..da71e104 100644 --- a/account_move_transactionid_import/parser/transactionid_file_parser.py +++ b/account_move_transactionid_import/parser/transactionid_file_parser.py @@ -3,7 +3,8 @@ import datetime from odoo.tools import ustr from odoo.addons.account_move_base_import.parser.file_parser import ( - FileParser, float_or_zero + FileParser, + float_or_zero, ) @@ -12,8 +13,13 @@ class TransactionIDFileParser(FileParser): bank statement. """ - def __init__(self, profile, ftype='csv', extra_fields=None, header=None, - **kwargs): + def __init__( + self, + profile, + ftype="csv", + extra_fields=None, + header=None, + **kwargs): """Add transaction_id in header keys :param char: profile: Reference to the profile :param char: ftype: extension of the file (could be csv or xls) @@ -23,22 +29,27 @@ class TransactionIDFileParser(FileParser): header """ conversion_dict = { - 'transaction_id': ustr, - 'label': ustr, - 'date': datetime.datetime, - 'amount': float_or_zero, - 'commission_amount': float_or_zero, + "transaction_id": ustr, + "label": ustr, + "date": datetime.datetime, + "amount": float_or_zero, + "commission_amount": float_or_zero, } super().__init__( - profile, extra_fields=conversion_dict, ftype=ftype, header=header, - **kwargs) + profile, + extra_fields=conversion_dict, + ftype=ftype, + header=header, + **kwargs + ) + self.support_multi_moves = True @classmethod def parser_for(cls, parser_name): """Used by the new_bank_statement_parser class factory. Return true if the providen name is generic_csvxls_transaction """ - return parser_name == 'generic_csvxls_transaction' + return parser_name == "generic_csvxls_transaction" def get_move_line_vals(self, line, *args, **kwargs): """This method must return a dict of vals that can be passed to create @@ -60,11 +71,19 @@ class TransactionIDFileParser(FileParser): In this generic parser, the commission is given for every line, so we store it for each one. """ - amount = line.get('amount', 0.0) + amount = line.get("amount", 0.0) return { - 'name': line.get('label', '/'), - 'date_maturity': line.get('date', datetime.datetime.now().date()), - 'credit': amount > 0.0 and amount or 0.0, - 'debit': amount < 0.0 and -amount or 0.0, - 'transaction_ref': line.get('transaction_id', '/'), + "name": line.get("label", "/"), + "date_maturity": line.get("date", datetime.datetime.now().date()), + "credit": amount > 0.0 and amount or 0.0, + "debit": amount < 0.0 and -amount or 0.0, + "ref": line.get("transaction_id", "/"), } + + def get_move_vals(self): + res = super().get_move_vals() + if "ref" in res: + res.pop("ref") + if res.get("name") == "/": + res["name"] = self.move_ref + return res diff --git a/account_move_transactionid_import/tests/data/completion_rule_data.xml b/account_move_transactionid_import/tests/data/completion_rule_data.xml new file mode 100644 index 00000000..45d680d2 --- /dev/null +++ b/account_move_transactionid_import/tests/data/completion_rule_data.xml @@ -0,0 +1,16 @@ + + + + + Match from Sales Order using transaction ID + 30 + get_from_transaction_id_and_so + + + + Match from Invoice using transaction ID + 40 + get_from_transaction_id_and_invoice + + + diff --git a/account_move_transactionid_import/data/statement.csv b/account_move_transactionid_import/tests/data/statement.csv similarity index 100% rename from account_move_transactionid_import/data/statement.csv rename to account_move_transactionid_import/tests/data/statement.csv diff --git a/account_move_transactionid_import/data/statement.xls b/account_move_transactionid_import/tests/data/statement.xls similarity index 100% rename from account_move_transactionid_import/data/statement.xls rename to account_move_transactionid_import/tests/data/statement.xls diff --git a/account_move_transactionid_import/tests/test_transactionid_import.py b/account_move_transactionid_import/tests/test_transactionid_import.py new file mode 100644 index 00000000..816902e9 --- /dev/null +++ b/account_move_transactionid_import/tests/test_transactionid_import.py @@ -0,0 +1,61 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +import base64 +import os + +from odoo.modules.module import get_module_resource +from odoo.addons.account_move_base_import.tests.test_base_import import ( + TestCodaImport, +) + + +class TestTransactionIdImport(TestCodaImport): + def test_multiline_csv(self): + """Test import from csv + """ + self.journal.write({"import_type": "generic_csvxls_transaction"}) + file_name = get_module_resource( + "account_move_transactionid_import", + "tests", + "data", + "statement.csv" + ) + move_ids = self._import_file_multi(file_name) + self._validate_imported_moves(move_ids) + + def test_multiline_xls(self): + """Test import from xls + """ + self.journal.write({"import_type": "generic_csvxls_transaction"}) + file_name = get_module_resource( + "account_move_transactionid_import", + "tests", + "data", + "statement.xls" + ) + move_ids = self._import_file_multi(file_name) + self._validate_imported_moves(move_ids) + + def _import_file_multi(self, file_name): + """ import a file using the wizard + return the create account.bank.statement object + """ + with open(file_name, "rb") as f: + content = f.read() + self.wizard = self.import_wizard_obj.create( + { + "journal_id": self.journal.id, + "input_statement": base64.b64encode(content), + "file_name": os.path.basename(file_name), + } + ) + res = self.wizard.import_statement() + return self.account_move_obj.browse(res["domain"][0][2]) + + def _validate_imported_moves(self, moves): + self.assertEqual(len(moves), 3) + transaction_ids = ["50969286", "51065326", "51179306"] + for i, move in enumerate(moves): + self.assertEqual(move.ref, transaction_ids[i]) + self.assertEqual(move.name, "statement") + self.assertEqual(3, len(move.line_ids))