details:   https://code.tryton.org/tryton/commit/bd2d0b0cc6fa
branch:    default
user:      Cédric Krier <[email protected]>
date:      Thu Jul 23 14:52:10 2026 +0200
description:
        Add CSV as import format for account statement
diffstat:

 modules/account_statement/CHANGELOG                                |    1 +
 modules/account_statement/doc/design.rst                           |   17 +
 modules/account_statement/exceptions.py                            |    5 +
 modules/account_statement/message.xml                              |    3 +
 modules/account_statement/pyproject.toml                           |    1 +
 modules/account_statement/statement.py                             |  278 
+++++++++-
 modules/account_statement/statement.xml                            |   54 +
 modules/account_statement/tests/scenario_account_statement_csv.rst |  122 ++++
 modules/account_statement/tests/statement.csv                      |    3 +
 modules/account_statement/tryton.cfg                               |    1 +
 modules/account_statement/view/statement_import_csv_form.xml       |   52 +
 modules/account_statement/view/statement_import_csv_list.xml       |    6 +
 modules/account_statement/view/statement_import_start_form.xml     |   11 +-
 13 files changed, 546 insertions(+), 8 deletions(-)

diffs (694 lines):

diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa modules/account_statement/CHANGELOG
--- a/modules/account_statement/CHANGELOG       Sat Aug 29 20:21:09 2026 +0300
+++ b/modules/account_statement/CHANGELOG       Thu Jul 23 14:52:10 2026 +0200
@@ -1,3 +1,4 @@
+* Add CSV as import format
 
 Version 8.0.0 - 2026-04-20
 --------------------------
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa modules/account_statement/doc/design.rst
--- a/modules/account_statement/doc/design.rst  Sat Aug 29 20:21:09 2026 +0300
+++ b/modules/account_statement/doc/design.rst  Thu Jul 23 14:52:10 2026 +0200
@@ -105,3 +105,20 @@
 
       .. |Financial --> Configuration --> Statements --> Statement Journals| 
replace:: :menuselection:`Financial --> Configuration --> Statements --> 
Statement Journals`
       __ https://demo.tryton.org/model/account.statement.journal
+
+.. _model-account.statement.import.csv:
+
+CSV Import
+==========
+
+A *CSV Import* defines the format of :abbr:`CSV (Comma-Separated Values)` files
+that can be used to `import statements <wizard-account.statement.import>`.
+
+.. seealso::
+
+   CSV Import can be found by opening the main menu item:
+
+      |Financial --> Configuration --> Statements --> CSV Imports|__
+
+      .. |Financial --> Configuration --> Statements --> CSV Imports| 
replace:: :menuselection:`Financial --> Configuration --> Statements --> CSV 
Imports`
+      __ https://demo.tryton.org/model/account.statement.import.csv
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa modules/account_statement/exceptions.py
--- a/modules/account_statement/exceptions.py   Sat Aug 29 20:21:09 2026 +0300
+++ b/modules/account_statement/exceptions.py   Thu Jul 23 14:52:10 2026 +0200
@@ -1,6 +1,7 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
 from trytond.exceptions import UserError, UserWarning
+from trytond.model.exceptions import ValidationError
 
 
 class ImportStatementError(UserError):
@@ -17,3 +18,7 @@
 
 class StatementPostError(UserError):
     pass
+
+
+class StatementImportCSVValidationError(ValidationError):
+    pass
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa modules/account_statement/message.xml
--- a/modules/account_statement/message.xml     Sat Aug 29 20:21:09 2026 +0300
+++ b/modules/account_statement/message.xml     Thu Jul 23 14:52:10 2026 +0200
@@ -52,5 +52,8 @@
         <record model="ir.message" id="msg_statement_import_error">
             <field name="text">The statement file could not be parsed with the 
following exception: "%(exception)s".</field>
         </record>
+        <record model="ir.message" 
id="msg_statement_import_csv_invalid_date_format">
+            <field name="text">Invalid date format "%(date_format)s" for the 
CSV import "%(record)s" with error: "%(error)s"</field>
+        </record>
     </data>
 </tryton>
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa modules/account_statement/pyproject.toml
--- a/modules/account_statement/pyproject.toml  Sat Aug 29 20:21:09 2026 +0300
+++ b/modules/account_statement/pyproject.toml  Thu Jul 23 14:52:10 2026 +0200
@@ -45,6 +45,7 @@
     'icons/**/*.svg',
     'tests/**/*.rst',
     'tests/**/*.json',
+    'tests/**/*.csv',
     ]
 exclude = ['doc']
 
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa modules/account_statement/statement.py
--- a/modules/account_statement/statement.py    Sat Aug 29 20:21:09 2026 +0300
+++ b/modules/account_statement/statement.py    Thu Jul 23 14:52:10 2026 +0200
@@ -1,7 +1,12 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
+
+import csv
+import datetime as dt
+import os.path
 from collections import defaultdict, namedtuple
 from decimal import Decimal
+from io import StringIO
 from itertools import groupby
 
 from sql import Null
@@ -25,8 +30,8 @@
 from trytond.wizard import Button, StateAction, StateView, Wizard
 
 from .exceptions import (
-    ImportStatementError, StatementPostError, StatementValidateError,
-    StatementValidateWarning)
+    ImportStatementError, StatementImportCSVValidationError,
+    StatementPostError, StatementValidateError, StatementValidateWarning)
 
 if config.getboolean('account_statement', 'filestore', default=False):
     file_id = 'origin_file_id'
@@ -1264,18 +1269,50 @@
 class ImportStatementStart(ModelView):
     __name__ = 'account.statement.import.start'
     company = fields.Many2One('company.company', "Company", required=True)
-    file_ = fields.Binary("File", required=True)
-    file_format = fields.Selection(
-        [(None, '')], "File Format", required=True, translate=False)
+    file_ = fields.Binary("File", required=True, filename='file_name')
+    file_name = fields.Char("File Name")
+    file_format = fields.Selection([
+            ('csv', "CSV"),
+            ], "File Format", required=True, translate=False)
+    csv_format = fields.Many2One(
+        'account.statement.import.csv', "CSV Format",
+        states={
+            'required': Eval('file_format') == 'csv',
+            'invisible': Eval('file_format') != 'csv',
+            })
+    csv_journal = fields.Many2One(
+        'account.statement.journal', "Journal",
+        domain=[
+            ('validation', '!=', 'balance'),
+            ],
+        states={
+            'required': Eval('file_format') == 'csv',
+            'invisible': Eval('file_format') != 'csv',
+            })
 
     @classmethod
-    def default_file_format(cls):
-        return None
+    def __setup__(cls):
+        super().__setup__()
+        cls.file_name.states = {
+            'required': Eval('file_format').in_(cls._file_name_required()),
+            }
+
+    @classmethod
+    def _file_name_required(cls):
+        return ['csv']
 
     @classmethod
     def default_company(cls):
         return Transaction().context.get('company')
 
+    @property
+    def file_name_used(self):
+        name = self.file_name
+        while True:
+            name, ext = os.path.splitext(name)
+            if not ext:
+                return name
+
 
 class ImportStatement(Wizard):
     __name__ = 'account.statement.import'
@@ -1308,6 +1345,233 @@
             action['views'].reverse()
         return action, data
 
+    def parse_csv(self):
+        csv_format = self.start.csv_format
+        file_ = StringIO(self.start.file_.decode(csv_format.encoding))
+        reader = csv_format.reader(file_)
+        for _ in range(csv_format.lines_to_skip):
+            next(reader, None)
+        statement = self.csv_statement()
+        origins = []
+        count = 0
+        for count, row in enumerate(reader, start=1):
+            origins.extend(self.csv_origin(row, csv_format))
+        statement.origins = origins
+        statement.total_amount = sum(o.amount for o in origins)
+        statement.number_of_lines = count
+        yield statement
+
+    def csv_statement(self):
+        pool = Pool()
+        Date = pool.get('ir.date')
+        Statement = pool.get('account.statement')
+
+        statement = Statement()
+        statement.name = self.start.file_name_used
+        statement.company = self.start.company
+        statement.journal = self.start.csv_journal
+        statement.date = Date.today()
+        return statement
+
+    def csv_origin(self, row, format_):
+        pool = Pool()
+        Origin = pool.get('account.statement.origin')
+
+        origin = Origin()
+        if format_.number_column is not None:
+            origin.number = row[format_.number_column]
+        origin.date = format_.parse_date(row[format_.date_column])
+        origin.amount = format_.parse_number(row[format_.amount_column])
+        origin.party = self.csv_party(row, format_)
+        if format_.description_column is not None:
+            origin.description = row[format_.description_column]
+        origin.information = self.csv_information(row)
+        return [origin]
+
+    def csv_party(self, row, format_):
+        pool = Pool()
+        Party = pool.get('party.party')
+        AccountNumber = pool.get('bank.account.number')
+
+        if format_.account_column is not None:
+            account_number = row[format_.account_column]
+            if account_number:
+                numbers = AccountNumber.search(['OR',
+                        ('number', '=', account_number),
+                        ('number_compact', '=', account_number),
+                        ])
+                if len(numbers) == 1:
+                    number, = numbers
+                    if number.account.owners:
+                        return number.account.owners[0]
+        if format_.party_column is not None:
+            party_name = row[format_.party_column]
+            if party_name:
+                parties = Party.search([('rec_name', 'ilike', party_name)])
+                if len(parties) == 1:
+                    party, = parties
+                    return party
+
+    def csv_information(self, row):
+        output = StringIO()
+        writer = csv.writer(
+            output,
+            delimiter=',',
+            quoting=csv.QUOTE_NONE,
+            escapechar='\\')
+        writer.writerow(row)
+        value = output.getvalue().strip()
+        return {
+            'csv_row': value,
+            }
+
+
+encodings = ["ascii", "big5", "big5hkscs", "cp037", "cp424", "cp437", "cp500",
+    "cp720", "cp737", "cp775", "cp850", "cp852", "cp855", "cp856", "cp857",
+    "cp858", "cp860", "cp861", "cp862", "cp863", "cp864", "cp865", "cp866",
+    "cp869", "cp874", "cp875", "cp932", "cp949", "cp950", "cp1006", "cp1026",
+    "cp1140", "cp1250", "cp1251", "cp1252", "cp1253", "cp1254", "cp1255",
+    "cp1256", "cp1257", "cp1258", "euc_jp", "euc_jis_2004", "euc_jisx0213",
+    "euc_kr", "gb2312", "gbk", "gb18030", "hz", "iso2022_jp", "iso2022_jp_1",
+    "iso2022_jp_2", "iso2022_jp_2004", "iso2022_jp_3", "iso2022_jp_ext",
+    "iso2022_kr", "latin_1", "iso8859_2", "iso8859_3", "iso8859_4",
+    "iso8859_5", "iso8859_6", "iso8859_7", "iso8859_8", "iso8859_9",
+    "iso8859_10", "iso8859_13", "iso8859_14", "iso8859_15", "iso8859_16",
+    "johab", "koi8_r", "koi8_u", "mac_cyrillic", "mac_greek", "mac_iceland",
+    "mac_latin2", "mac_roman", "mac_turkish", "ptcp154", "shift_jis",
+    "shift_jis_2004", "shift_jisx0213", "utf_32", "utf_32_be", "utf_32_le",
+    "utf_16", "utf_16_be", "utf_16_le", "utf_7", "utf_8", "utf_8_sig"]
+
+
+class StatementImportCSV(ModelSQL, ModelView):
+    __name__ = 'account.statement.import.csv'
+
+    name = fields.Char("Name", required=True)
+    encoding = fields.Selection(
+        [(e, e) for e in encodings],
+        "Encoding", required=True, translate=False)
+    delimiter = fields.Char("Delimiter", size=1, required=True, strip=False)
+    quotechar = fields.Char("Quote char", size=1, strip=False)
+    lines_to_skip = fields.Integer("Lines to Skip", required=True)
+    date_format = fields.Char(
+        "Date Format", required=True, strip=False,
+        help="The format of the date using the 1989 C standard.")
+    decimal_point = fields.Char(
+        "Decimal Separator", required=True, strip=False)
+    thousands_sep = fields.Char("Thousands Separator", strip=False)
+
+    number_column = fields.Integer(
+        "Number",
+        domain=['OR',
+            ('number_column', '=', None),
+            ('number_column', '>=', 0),
+            ])
+    date_column = fields.Integer(
+        "Date", required=True,
+        domain=[('date_column', '>=', 0)])
+    amount_column = fields.Integer(
+        "Amount", required=True,
+        domain=[('amount_column', '>=', 0)])
+    account_column = fields.Integer(
+        "Account Number",
+        domain=['OR',
+            ('account_column', '=', None),
+            ('account_column', '>=', 0),
+            ])
+    party_column = fields.Integer(
+        "Party",
+        domain=['OR',
+            ('party_column', '=', None),
+            ('party_column', '>=', 0),
+            ])
+    description_column = fields.Integer(
+        "Description",
+        domain=['OR',
+            ('description_column', '=', None),
+            ('description_column', '>=', 0),
+            ])
+
+    @classmethod
+    def default_encoding(cls):
+        return 'utf_8'
+
+    @classmethod
+    def default_delimiter(cls):
+        return ','
+
+    @classmethod
+    def default_quotechar(cls):
+        return '"'
+
+    @classmethod
+    def default_lines_to_skip(cls):
+        return 0
+
+    @classmethod
+    def default_date_format(cls):
+        pool = Pool()
+        Lang = pool.get('ir.lang')
+        lang = Lang.get()
+        return lang.date
+
+    @classmethod
+    def default_decimal_point(cls):
+        pool = Pool()
+        Lang = pool.get('ir.lang')
+        lang = Lang.get()
+        return lang.mon_decimal_point
+
+    @classmethod
+    def default_thousands_sep(cls):
+        pool = Pool()
+        Lang = pool.get('ir.lang')
+        lang = Lang.get()
+        return lang.mon_thousands_sep
+
+    def reader(self, csvfile):
+        return csv.reader(csvfile, **self.fmtparams)
+
+    @property
+    def fmtparams(self):
+        return {
+            'delimiter': self.delimiter,
+            'quotechar': self.quotechar,
+            }
+
+    @classmethod
+    def validate_fields(cls, records, field_names):
+        super().validate_fields(records, field_names)
+        cls.check_date_format(records, field_names)
+
+    @classmethod
+    def check_date_format(cls, records, field_names=None):
+        if field_names and 'date_format' not in field_names:
+            return
+        for record in records:
+            if record.date_format:
+                try:
+                    dt.datetime.strptime(
+                        dt.datetime.now().strftime(record.date_format),
+                        record.date_format)
+                except ValueError as e:
+                    raise StatementImportCSVValidationError(
+                        gettext(
+                            'account_statement'
+                            '.msg_statement_import_csv_invalid_date_format',
+                            date_format=record.date_format,
+                            record=record.rec_name,
+                            error=e)) from e
+
+    def parse_date(self, value):
+        return dt.datetime.strptime(value, self.date_format).date()
+
+    def parse_number(self, value):
+        if self.thousands_sep:
+            value = value.replace(self.thousands_sep, '')
+        if self.decimal_point:
+            value = value.replace(self.decimal_point, '.')
+        return Decimal(value)
+
 
 class ReconcileStatement(Wizard):
     __name__ = 'account.statement.reconcile'
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa modules/account_statement/statement.xml
--- a/modules/account_statement/statement.xml   Sat Aug 29 20:21:09 2026 +0300
+++ b/modules/account_statement/statement.xml   Thu Jul 23 14:52:10 2026 +0200
@@ -314,6 +314,12 @@
             <field name="perm_delete" eval="False"/>
         </record>
 
+        <record model="account.statement.origin.information" 
id="information_csv_row">
+            <field name="name">csv_row</field>
+            <field name="string">Row</field>
+            <field name="type_">char</field>
+        </record>
+
         <record model="ir.ui.view" id="statement_import_start_view_form">
             <field name="model">account.statement.import.start</field>
             <field name="type">form</field>
@@ -346,6 +352,54 @@
             <field name="group" ref="group_statement"/>
         </record>
 
+        <record model="ir.ui.view" id="statement_import_csv_view_form">
+            <field name="model">account.statement.import.csv</field>
+            <field name="type">form</field>
+            <field name="name">statement_import_csv_form</field>
+        </record>
+
+        <record model="ir.ui.view" id="statement_import_csv_view_list">
+            <field name="model">account.statement.import.csv</field>
+            <field name="type">tree</field>
+            <field name="name">statement_import_csv_list</field>
+        </record>
+
+        <record model="ir.action.act_window" 
id="act_statement_import_csv_form">
+            <field name="name">CSV Imports</field>
+            <field name="res_model">account.statement.import.csv</field>
+        </record>
+        <record model="ir.action.act_window.view" 
id="act_statement_import_csv_form_view1">
+            <field name="sequence" eval="10"/>
+            <field name="view" ref="statement_import_csv_view_list"/>
+            <field name="act_window" ref="act_statement_import_csv_form"/>
+        </record>
+        <record model="ir.action.act_window.view" 
id="act_statement_import_csv_form_view2">
+            <field name="sequence" eval="20"/>
+            <field name="view" ref="statement_import_csv_view_form"/>
+            <field name="act_window" ref="act_statement_import_csv_form"/>
+        </record>
+        <menuitem
+            parent="menu_statement_configuration"
+            action="act_statement_import_csv_form"
+            sequence="30"
+            id="menu_statement_import_csv_form"/>
+
+        <record model="ir.model.access" id="access_statement_import_csv">
+            <field name="model">account.statement.import.csv</field>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="False"/>
+            <field name="perm_create" eval="False"/>
+            <field name="perm_delete" eval="False"/>
+        </record>
+        <record model="ir.model.access" 
id="access_statement_import_csv_account_admin">
+            <field name="model">account.statement.import.csv</field>
+            <field name="group" ref="account.group_account_admin"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="True"/>
+            <field name="perm_create" eval="True"/>
+            <field name="perm_delete" eval="True"/>
+        </record>
+
         <record model="ir.action.wizard" id="act_reconcile">
             <field name="name">Reconcile Statements</field>
             <field name="wiz_name">account.statement.reconcile</field>
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa 
modules/account_statement/tests/scenario_account_statement_csv.rst
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/account_statement/tests/scenario_account_statement_csv.rst        
Thu Jul 23 14:52:10 2026 +0200
@@ -0,0 +1,122 @@
+==============================
+Account Statement CSV Scenario
+==============================
+
+Imports::
+
+    >>> from proteus import Model, Wizard
+    >>> from trytond.modules.account.tests.tools import create_chart, 
get_accounts
+    >>> from trytond.modules.company.tests.tools import create_company
+    >>> from trytond.tests.tools import activate_modules, assertEqual
+    >>> from trytond.tools import file_open
+
+Activate modules::
+
+    >>> config = activate_modules(
+    ...     'account_statement',
+    ...     create_company, create_chart)
+
+    >>> AccountJournal = Model.get('account.journal')
+    >>> Bank = Model.get('bank')
+    >>> BankAccount = Model.get('bank.account')
+    >>> CSV = Model.get('account.statement.import.csv')
+    >>> Party = Model.get('party.party')
+    >>> StatementJournal = Model.get('account.statement.journal')
+
+Get accounts::
+
+    >>> accounts = get_accounts()
+
+Create parties::
+
+    >>> customer = Party(name="Customer")
+    >>> customer.save()
+    >>> bank_party = Party(name="Bank")
+    >>> bank_party.save()
+
+Create bank account::
+
+    >>> bank = Bank()
+    >>> bank.party = bank_party
+    >>> bank.save()
+    >>> bank_account = BankAccount()
+    >>> bank_account.bank = bank
+    >>> bank_account.owners.append(customer)
+    >>> bank_account_number = bank_account.numbers.new()
+    >>> bank_account_number.type = 'iban'
+    >>> bank_account_number.number = 'BE47435000000080'
+    >>> bank_account.save()
+
+Setup statement journal::
+
+    >>> account_journal, = AccountJournal.find([('code', '=', 'STA')], limit=1)
+    >>> journal = StatementJournal(
+    ...     name="Bank",
+    ...     journal=account_journal,
+    ...     account=accounts['cash'],
+    ...     validation='amount')
+    >>> journal.save()
+
+Setup CSV import::
+
+    >>> csv = CSV(name="CSV Bank")
+    >>> csv.lines_to_skip = 1
+    >>> csv.date_format = '%d/%m/%Y'
+    >>> csv.decimal_point = ','
+    >>> csv.thousands_sep = '.'
+    >>> csv.number_column = 0
+    >>> csv.date_column = 1
+    >>> csv.amount_column = 2
+    >>> csv.account_column = 3
+    >>> csv.party_column = 4
+    >>> csv.description_column = 5
+    >>> csv.save()
+
+Import CSV file::
+
+    >>> statement_import = Wizard('account.statement.import')
+    >>> with file_open('account_statement/tests/statement.csv', mode='rb') as 
fp:
+    ...     statement_import.form.file_ = fp.read()
+    >>> statement_import.form.file_name = '001.csv'
+    >>> statement_import.form.file_format = 'csv'
+    >>> statement_import.form.csv_format = csv
+    >>> statement_import.form.csv_journal = journal
+    >>> statement_import.execute('import_')
+
+Check statement::
+
+    >>> (statement,), = statement_import.actions
+    >>> statement.name
+    '001'
+    >>> statement.total_amount
+    Decimal('980.50')
+    >>> statement.number_of_lines
+    2
+    >>> len(statement.origins)
+    2
+
+    >>> origin = statement.origins[0]
+    >>> origin.number
+    '0001'
+    >>> origin.date
+    datetime.date(2026, 1, 1)
+    >>> origin.amount
+    Decimal('1000.50')
+    >>> assertEqual(origin.party, customer)
+    >>> origin.description
+    'description'
+    >>> origin.information['csv_row']
+    '0001,01/01/2026,1.000\\,50,BE47435000000080,unknown,description'
+
+    >>> origin = statement.origins[1]
+    >>> origin.number
+    '0002'
+    >>> origin.date
+    datetime.date(2026, 1, 1)
+    >>> origin.amount
+    Decimal('-20')
+    >>> assertEqual(origin.party, customer)
+    >>> origin.description
+    ''
+    >>> origin.information['csv_row']
+    '0002,01/01/2026,-20,,Customer,'
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa 
modules/account_statement/tests/statement.csv
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/account_statement/tests/statement.csv     Thu Jul 23 14:52:10 
2026 +0200
@@ -0,0 +1,3 @@
+number,date,amount,account,party,description
+0001,01/01/2026,"1.000,50",BE47435000000080,unknown,description
+0002,01/01/2026,-20,,Customer,
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa modules/account_statement/tryton.cfg
--- a/modules/account_statement/tryton.cfg      Sat Aug 29 20:21:09 2026 +0300
+++ b/modules/account_statement/tryton.cfg      Thu Jul 23 14:52:10 2026 +0200
@@ -26,6 +26,7 @@
     statement.Origin
     statement.OriginInformation
     statement.ImportStatementStart
+    statement.StatementImportCSV
 wizard:
     party.Replace
     statement.ImportStatement
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa 
modules/account_statement/view/statement_import_csv_form.xml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/account_statement/view/statement_import_csv_form.xml      Thu Jul 
23 14:52:10 2026 +0200
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<form>
+    <label name="name"/>
+    <field name="name" colspan="3"/>
+
+    <separator string="Format" id="format" colspan="4"/>
+    <label name="encoding"/>
+    <field name="encoding"/>
+    <label name="lines_to_skip"/>
+    <field name="lines_to_skip"/>
+
+    <label name="delimiter"/>
+    <field name="delimiter"/>
+    <label name="quotechar"/>
+    <field name="quotechar"/>
+
+    <label name="date_format"/>
+    <field name="date_format"/>
+    <newline/>
+
+    <label name="decimal_point"/>
+    <field name="decimal_point"/>
+    <label name="thousands_sep"/>
+    <field name="thousands_sep"/>
+
+    <separator string="Columns" id="columns" colspan="4"/>
+    <label name="number_column"/>
+    <field name="number_column"/>
+    <newline/>
+
+    <label name="date_column"/>
+    <field name="date_column"/>
+    <newline/>
+
+    <label name="amount_column"/>
+    <field name="amount_column"/>
+    <newline/>
+
+    <label name="account_column"/>
+    <field name="account_column"/>
+    <newline/>
+
+    <label name="party_column"/>
+    <field name="party_column"/>
+    <newline/>
+
+    <label name="description_column"/>
+    <field name="description_column"/>
+    <newline/>
+</form>
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa 
modules/account_statement/view/statement_import_csv_list.xml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/account_statement/view/statement_import_csv_list.xml      Thu Jul 
23 14:52:10 2026 +0200
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tree>
+    <field name="name" expand="2"/>
+</tree>
diff -r 8ba5b9ce4398 -r bd2d0b0cc6fa 
modules/account_statement/view/statement_import_start_form.xml
--- a/modules/account_statement/view/statement_import_start_form.xml    Sat Aug 
29 20:21:09 2026 +0300
+++ b/modules/account_statement/view/statement_import_start_form.xml    Thu Jul 
23 14:52:10 2026 +0200
@@ -5,8 +5,17 @@
     <label name="company"/>
     <field name="company"/>
     <newline/>
+
     <label name="file_"/>
-    <field name="file_"/>
+    <field name="file_" filename_visible="1" colspan="3"/>
+
     <label name="file_format"/>
     <field name="file_format"/>
+    <newline/>
+
+    <label name="csv_format"/>
+    <field name="csv_format" widget="selection"/>
+    <label name="csv_journal"/>
+    <field name="csv_journal" widget="selection"/>
+    <newline/>
 </form>

Reply via email to