Перейти до вмісту

Технічне завдання: Гнучкий модуль імпорту банківських виписок у K2 ERP

Матеріал з K2 ERP Wiki

1. Загальна інформація

1.1. Назва задачі

Створення гнучкого налаштовуваного модуля імпорту банківських виписок у K2 ERP.

1.2. Мета розробки

Метою розробки є створення універсального механізму імпорту банківських виписок, який дозволить K2 ERP приймати виписки з будь-якого українського банку без необхідності доробки програмного коду для кожного нового формату.

Модуль має забезпечити:

  • імпорт банківських виписок з файлів різних форматів;
  • автоматичне розпізнавання відомих форматів;
  • ручне налаштування мапінгу для невідомих форматів;
  • збереження шаблонів імпорту для повторного використання;
  • приведення всіх зовнішніх форматів до єдиної внутрішньої структури K2 ERP;
  • попередній перегляд результатів імпорту;
  • валідацію та дедублікацію операцій;
  • журналювання та аудит імпорту;
  • можливість додавання нового формату банку без зміни програмного коду.

1.3. Основна бізнес-проблема

В українських банках відсутній єдиний практичний формат клієнтської банківської виписки у CSV, DBF або Excel, який однаково використовується всіма банками.

Різні банки можуть використовувати:

  • різні типи файлів;
  • різні назви колонок;
  • різне кодування;
  • різні правила визначення дебету та кредиту;
  • різний формат дат;
  • різну структуру контрагентів;
  • різні API;
  • різні версії одного й того самого формату в межах одного банку.

Тому модуль має бути не набором жорстко закодованих імпортів, а гнучкою платформою налаштування імпорту банківських виписок.

1.4. Основна ідея рішення

Усі зовнішні формати виписок мають перетворюватися у єдиний внутрішній формат K2 ERP.

Будь-яка банківська виписка
        ↓
Визначення формату
        ↓
Парсер або шаблон мапінгу
        ↓
Єдина внутрішня структура K2 ERP
        ↓
Перевірка
        ↓
Попередній перегляд
        ↓
Створення банківських операцій у K2 ERP

2. Область застосування

Модуль використовується в K2 ERP для завантаження банківських виписок у бухгалтерський, фінансовий або управлінський облік.

Модуль має підтримувати імпорт з таких джерел:

  • файл, завантажений користувачем;
  • файл, отриманий із клієнт-банку;
  • файл, сформований банківським API;
  • відповідь API банку;
  • стандартизований XML ISO 20022 camt.053;
  • ручно налаштований шаблон імпорту.

3. Терміни та скорочення

Термін Опис
Банківська виписка Файл або відповідь API, що містить рух коштів за банківським рахунком за певний період.
Парсер Python-функція або набір функцій, які читають конкретний формат виписки і перетворюють його у внутрішній формат K2 ERP.
Шаблон імпорту Налаштування, яке описує структуру файлу, відповідність колонок, правила сум, дат, дебету та кредиту.
Мапінг Зіставлення колонок або полів зовнішньої виписки з полями K2 ERP.
Preview Попередній перегляд результату імпорту до створення реальних банківських операцій.
Commit Остаточне підтвердження імпорту і створення документів або операцій у K2 ERP.
UETR Унікальний ідентифікатор платежу, якщо він присутній у банківській виписці.
ISO 20022 camt.053 XML-формат банківської виписки за рахунком.

4. Підтримувані типи файлів

Модуль має підтримувати такі формати:

Формат Опис Обов’язковість
CSV Текстовий файл з роздільниками Обов’язково
DBF Табличний формат, поширений у клієнт-банках Обов’язково
XLS Excel 97–2003 Бажано
XLSX Сучасний Excel-формат Обов’язково
XML XML-виписки банків, зокрема ISO 20022 camt.053 Обов’язково
JSON Відповіді API банків Бажано
TXT Текстові виписки довільної структури Бажано

5. Загальний принцип роботи модуля

Модуль має працювати за таким сценарієм:

  1. Користувач відкриває форму імпорту банківської виписки у K2 ERP.
  2. Користувач вибирає організацію та банківський рахунок.
  3. Користувач завантажує файл або вибирає API-джерело.
  4. Система визначає тип файлу.
  5. Система визначає кодування, роздільник, структуру колонок або XML/JSON-схему.
  6. Система шукає відповідний шаблон імпорту.
  7. Якщо шаблон знайдено — система застосовує його автоматично.
  8. Якщо шаблон не знайдено — система відкриває майстер ручного мапінгу.
  9. Система читає рядки виписки.
  10. Система приводить рядки до внутрішньої структури K2 ERP.
  11. Система виконує валідацію.
  12. Система виконує дедублікацію.
  13. Система показує користувачу попередній перегляд.
  14. Користувач підтверджує імпорт.
  15. Система створює банківські операції або документи K2 ERP.
  16. Система зберігає журнал імпорту.

6. Архітектура модуля відповідно до підходу K2 ERP Python

Модуль імпорту банківських виписок має бути реалізований як налаштовуваний Python-модуль K2 ERP, який викликається з інтерфейсу K2 ERP та працює з внутрішніми таблицями, довідниками, документами й журналами системи.

Модуль не повинен вимагати створення окремого вебзастосунку, окремого Flask/FastAPI-сервера або зовнішнього UI. Візуальна частина має використовувати стандартні механізми K2 ERP: форми, таблиці, дії, меню, редактор скриптів, стандартні grid-компоненти та права доступу.

6.1. Принцип реалізації

Основна логіка імпорту має бути винесена в Python-скрипти K2 ERP.

Користувач у K2 ERP
        ↓
Форма імпорту банківської виписки
        ↓
Python-скрипт імпорту
        ↓
Визначення формату файлу
        ↓
Застосування шаблону або ручного мапінгу
        ↓
Запис у тимчасові таблиці імпорту
        ↓
Попередній перегляд
        ↓
Підтвердження користувачем
        ↓
Створення банківських операцій у K2 ERP

6.2. Рекомендована структура Python-скриптів

Скрипт Призначення
bank_import_main.py Головна точка входу модуля імпорту.
bank_import_detect.py Визначення типу файлу, кодування, роздільника та шаблону.
bank_import_csv.py Обробка CSV-файлів.
bank_import_dbf.py Обробка DBF-файлів.
bank_import_xlsx.py Обробка XLS/XLSX-файлів.
bank_import_camt053.py Обробка XML ISO 20022 camt.053.
bank_import_mapping.py Застосування правил мапінгу.
bank_import_validate.py Валідація рядків виписки.
bank_import_deduplicate.py Пошук дублікатів.
bank_import_commit.py Остаточне створення операцій у K2 ERP.
bank_import_api_privat.py Імпорт через API ПриватБанку.
bank_import_api_mono.py Імпорт через API monobank.
bank_import_utils.py Допоміжні функції: дати, суми, IBAN, JSON, хеші.

6.3. Рекомендована структура модуля

k2bankimport/
    __init__.py
    bank_import_main.py
    bank_import_detect.py
    bank_import_csv.py
    bank_import_dbf.py
    bank_import_xlsx.py
    bank_import_camt053.py
    bank_import_mapping.py
    bank_import_validate.py
    bank_import_deduplicate.py
    bank_import_commit.py
    bank_import_api_privat.py
    bank_import_api_mono.py
    bank_import_utils.py

Усі скрипти мають бути орієнтовані на виклик із K2 ERP, а не на самостійний запуск як окремий вебсервіс.

6.4. Важлива архітектурна вимога

У ТЗ не потрібно жорстко закладати зовнішні controllers/services, якщо це не є стандартом K2 ERP.

Замість архітектури виду:

FileUploadController
BankApiController
ParserRegistry
ValidationService
ImportCommitService

для K2 ERP Python потрібно використовувати логіку:

Форма K2 ERP
Дія меню K2 ERP
Python-скрипт імпорту
Таблиці налаштувань K2 ERP
Таблиці попереднього імпорту
Шаблони мапінгу
Функції парсингу
Функції валідації
Функції створення документів K2 ERP
Журнал аудиту

7. Внутрішня універсальна модель даних

7.1. Об’єкт BankStatementImport

Це заголовок імпорту банківської виписки.

Поле Тип Опис
id UUID / bigint Ідентифікатор імпорту.
source_type enum FILE / API / MANUAL.
org_id FK Організація в K2 ERP.
bank_id FK Банк у довіднику K2 ERP.
bank_code string Код банку.
bank_name string Назва банку.
account_id FK Банківський рахунок K2 ERP.
account_iban string IBAN рахунку.
currency string Валюта.
period_from date Початок періоду.
period_to date Кінець періоду.
opening_balance decimal Вхідний залишок.
closing_balance decimal Вихідний залишок.
source_file_id UUID / FK Посилання на завантажений файл.
template_id FK Використаний шаблон імпорту.
parser_code string Код використаного парсера.
parser_version string Версія парсера.
status enum DRAFT / PREVIEW / VALIDATED / IMPORTED / ERROR.
rows_total integer Загальна кількість рядків.
rows_ok integer Кількість коректних рядків.
rows_warning integer Кількість рядків з попередженнями.
rows_error integer Кількість рядків з помилками.
created_at datetime Дата створення.
created_by user_id Користувач.
imported_at datetime Дата остаточного імпорту.
imported_by user_id Користувач, який підтвердив імпорт.

7.2. Об’єкт BankStatementImportRow

Це рядок імпорту банківської виписки.

Поле Тип Опис
id UUID / bigint Ідентифікатор рядка.
statement_import_id FK Посилання на імпорт.
row_number integer Номер рядка у файлі.
operation_date datetime Дата операції.
document_date datetime Дата документа.
value_date date Дата валютування.
document_number string Номер документа.
direction enum DEBIT / CREDIT.
amount decimal Сума операції.
currency string Валюта.
payer_name string Платник.
payer_edrpou string ЄДРПОУ платника.
payer_iban string IBAN платника.
payer_mfo string МФО платника.
receiver_name string Отримувач.
receiver_edrpou string ЄДРПОУ отримувача.
receiver_iban string IBAN отримувача.
receiver_mfo string МФО отримувача.
counterparty_name string Контрагент.
counterparty_edrpou string ЄДРПОУ контрагента.
counterparty_iban string IBAN контрагента.
counterparty_mfo string МФО контрагента.
purpose text Призначення платежу.
uetr string Унікальний ідентифікатор платежу.
external_transaction_id string Ідентифікатор операції у банку або API.
raw_row_json json Оригінальні дані рядка.
hash_key string Ключ дедублікації.
validation_status enum OK / WARNING / ERROR.
import_status enum NEW / IMPORTED / SKIPPED / ERROR.
error_message text Повідомлення про помилку.
warning_message text Повідомлення з попередженням.
created_doc_id FK Посилання на створений документ або операцію K2 ERP.

8. Таблиці K2 ERP для модуля

8.1. Таблиця k2_bank_import

Поле Призначення
id Ідентифікатор імпорту.
org_id Організація.
account_id Банківський рахунок K2 ERP.
bank_id Банк.
file_id Завантажений файл.
template_id Використаний шаблон.
status Статус імпорту.
rows_total Загальна кількість рядків.
rows_ok Кількість коректних рядків.
rows_warning Кількість рядків з попередженнями.
rows_error Кількість рядків з помилками.
created_at Дата створення.
created_by Користувач.
imported_at Дата імпорту.
imported_by Користувач, який підтвердив імпорт.

8.2. Таблиця k2_bank_import_row

Поле Призначення
id Ідентифікатор рядка.
import_id Посилання на імпорт.
row_number Номер рядка у файлі.
operation_date Дата операції.
document_number Номер документа.
direction DEBIT / CREDIT.
amount Сума.
currency Валюта.
counterparty_name Контрагент.
counterparty_edrpou ЄДРПОУ контрагента.
counterparty_iban IBAN контрагента.
purpose Призначення платежу.
uetr UETR.
raw_row_json Оригінальний рядок.
hash_key Ключ дедублікації.
status OK / WARNING / ERROR / IMPORTED / SKIPPED.
error_message Текст помилки.
created_doc_id Створений документ K2 ERP.

8.3. Таблиця k2_bank_import_template

Поле Призначення
id Ідентифікатор шаблону.
name Назва шаблону.
code Технічний код шаблону.
bank_id Банк або NULL для універсального шаблону.
file_type CSV / DBF / XLS / XLSX / XML / JSON / TXT.
encoding Кодування.
delimiter Роздільник.
header_row Рядок заголовків.
mapping_json Мапінг колонок.
rules_json Правила обробки.
signature_json Сигнатура автоматичного визначення.
parser_code Код парсера.
is_system Системний шаблон.
is_active Активність.
version Версія.
created_at Дата створення.
created_by Автор.
updated_at Дата зміни.
updated_by Автор зміни.

8.4. Таблиця k2_bank_import_log

Поле Призначення
id Ідентифікатор запису журналу.
import_id Посилання на імпорт.
event_type Тип події.
event_message Повідомлення.
event_data_json Додаткові дані.
created_at Дата події.
created_by Користувач або система.

9. Реєстр шаблонів імпорту

9.1. Призначення шаблонів

Шаблон імпорту описує, як саме потрібно читати конкретний формат банківської виписки.

Шаблон має дозволити налаштувати імпорт без зміни Python-коду.

9.2. Дані шаблону

Шаблон має зберігати:

  • назву шаблону;
  • банк;
  • тип файлу;
  • кодування;
  • роздільник;
  • номер рядка заголовків;
  • список обов’язкових колонок;
  • список необов’язкових колонок;
  • відповідність колонок полям K2 ERP;
  • правила визначення дебету/кредиту;
  • правила визначення суми;
  • правила визначення контрагента;
  • правила перетворення дат;
  • правила очищення тексту;
  • сигнатуру автоматичного розпізнавання.

9.3. Приклад шаблону CSV

{
  "code": "CSV_DATA_VYP_MFO_AC_OKPO_V1",
  "name": "CSV з DATA_VYP/MFO/AC/OKPO",
  "file_type": "CSV",
  "encoding": "CP1251",
  "delimiter": ";",
  "header_row": 1,
  "required_columns": [
    "DATA_VYP",
    "MFO",
    "AC",
    "OKPO",
    "NAME",
    "ND",
    "DATA_D",
    "DK",
    "PURPOSE"
  ],
  "optional_columns": [
    "DB_IBAN",
    "CR_IBAN",
    "UETR"
  ],
  "mapping": {
    "operation_date": "DATA_D",
    "document_number": "ND",
    "counterparty_name": "NAME_KOR",
    "counterparty_edrpou": "OKPO_KOR",
    "purpose": "PURPOSE",
    "debit_amount": "DB_SUM_NOM",
    "credit_amount": "CR_SUM_NOM",
    "debit_iban": "DB_IBAN",
    "credit_iban": "CR_IBAN",
    "uetr": "UETR"
  },
  "direction_rule": {
    "type": "field_value",
    "field": "DK",
    "debit_values": ["0", "D", "DB"],
    "credit_values": ["1", "C", "CR"]
  },
  "amount_rule": {
    "type": "debit_credit_columns",
    "debit_column": "DB_SUM_NOM",
    "credit_column": "CR_SUM_NOM",
    "fallback_amount_column": "SUM_PD_NOM"
  }
}

10. Визначення формату файлу

10.1. Що має визначати система

Після завантаження файлу система має автоматично визначити:

  • тип файлу;
  • кодування;
  • роздільник;
  • наявність заголовка;
  • номер рядка з заголовками;
  • список колонок;
  • кількість колонок;
  • формат дат;
  • наявність колонок дебету/кредиту;
  • наявність IBAN;
  • наявність ЄДРПОУ/ОКПО;
  • наявність UETR;
  • можливий шаблон банку.

10.2. Приклад функції визначення метаданих

def detect_file_metadata(file_info):
    """
    Визначає базові технічні параметри файлу банківської виписки.
    """

    return {
        "file_type": "CSV",
        "encoding": "CP1251",
        "delimiter": ";",
        "has_header": True,
        "header_row": 1,
        "columns": [
            "DATA_VYP",
            "MFO",
            "AC",
            "OKPO",
            "NAME",
            "ND",
            "DATA_D",
            "DK",
            "PURPOSE",
            "DB_IBAN",
            "CR_IBAN",
            "UETR"
        ]
    }

10.3. Логіка автоматичного визначення шаблону

Система має розраховувати коефіцієнт відповідності шаблону.

Критерій Вага
Збіг обов’язкових колонок 50%
Збіг необов’язкових колонок 15%
Збіг кодування 10%
Збіг роздільника 10%
Збіг формату дат 10%
Збіг специфічних ознак банку 5%

Правила:

Score Дія
>= 85% Автоматично застосувати шаблон.
60–84% Запропонувати користувачу підтвердити шаблон.
< 60% Відкрити майстер ручного мапінгу.

11. Python-реєстр парсерів

11.1. Загальний підхід

Замість Java-подібного interface доцільно використовувати простий реєстр Python-функцій або класів.

PARSERS = {
    "CSV_GENERIC": {
        "detect": detect_generic_csv,
        "parse": parse_generic_csv
    },
    "CSV_DATA_VYP_MFO_AC_OKPO": {
        "detect": detect_csv_data_vyp,
        "parse": parse_csv_data_vyp
    },
    "DBF_GENERIC": {
        "detect": detect_generic_dbf,
        "parse": parse_generic_dbf
    },
    "XLSX_GENERIC": {
        "detect": detect_generic_xlsx,
        "parse": parse_generic_xlsx
    },
    "ISO20022_CAMT053": {
        "detect": detect_camt053,
        "parse": parse_camt053
    }
}

11.2. Вимоги до парсера

Кожен парсер має:

  • перевіряти, чи може він обробити файл;
  • читати дані файлу;
  • перетворювати рядки у внутрішній формат;
  • не створювати документи K2 ERP напряму;
  • повертати структурований результат;
  • повертати помилки без аварійного завершення;
  • зберігати raw-дані рядків.

11.3. Універсальний формат рядка після парсингу

Кожен парсер, незалежно від типу файлу, має повертати рядки в єдиному форматі:

{
    "row_number": 1,
    "operation_date": "2026-05-25",
    "document_date": "2026-05-25",
    "document_number": "12345",
    "direction": "CREDIT",
    "amount": 1500.00,
    "currency": "UAH",
    "payer_name": "ТОВ Приклад",
    "payer_edrpou": "12345678",
    "payer_iban": "UA123456789000000000000000001",
    "receiver_name": "ТОВ Отримувач",
    "receiver_edrpou": "87654321",
    "receiver_iban": "UA123456789000000000000000002",
    "counterparty_name": "ТОВ Приклад",
    "counterparty_edrpou": "12345678",
    "counterparty_iban": "UA123456789000000000000000001",
    "purpose": "Оплата за товар згідно рахунку",
    "uetr": "",
    "raw_row": {}
}

12. Головний сценарій Python-обробки

12.1. Підготовка виписки до імпорту

def import_bank_statement(k2, file_id, account_id, template_id=None):
    """
    Головна функція підготовки банківської виписки до імпорту.

    k2          - об'єкт доступу до середовища K2 ERP
    file_id     - ідентифікатор завантаженого файлу
    account_id  - банківський рахунок у K2 ERP
    template_id - шаблон імпорту, якщо користувач вибрав його вручну
    """

    file_info = load_uploaded_file(k2, file_id)

    file_meta = detect_file_metadata(file_info)

    if template_id:
        template = load_import_template(k2, template_id)
    else:
        template = detect_import_template(k2, file_meta)

    if not template:
        return {
            "status": "need_mapping",
            "message": "Формат виписки не розпізнано. Потрібне ручне налаштування мапінгу.",
            "file_meta": file_meta
        }

    raw_rows = read_statement_rows(file_info, file_meta, template)

    mapped_rows = apply_mapping(raw_rows, template)

    validation_result = validate_statement_rows(k2, mapped_rows, account_id)

    import_id = save_import_preview(
        k2=k2,
        file_id=file_id,
        account_id=account_id,
        template=template,
        rows=validation_result["rows"]
    )

    return {
        "status": "preview",
        "import_id": import_id,
        "message": "Виписку підготовлено до імпорту",
        "rows_count": len(validation_result["rows"]),
        "errors_count": validation_result["errors_count"],
        "warnings_count": validation_result["warnings_count"]
    }

12.2. Остаточне підтвердження імпорту

def commit_bank_statement_import(k2, import_id, user_id):
    """
    Остаточне створення банківських операцій у K2 ERP
    на основі попередньо підготовленого імпорту.
    """

    import_header = load_import_header(k2, import_id)
    rows = load_import_rows(k2, import_id)

    created_count = 0
    skipped_count = 0
    error_count = 0

    for row in rows:
        if row["status"] == "ERROR":
            error_count += 1
            continue

        if is_duplicate(k2, row):
            mark_row_skipped(k2, row["id"], "Дублікат операції")
            skipped_count += 1
            continue

        try:
            doc_id = create_bank_operation_in_k2(k2, import_header, row)
            mark_row_imported(k2, row["id"], doc_id)
            created_count += 1
        except Exception as exc:
            mark_row_error(k2, row["id"], str(exc))
            error_count += 1

    update_import_status(
        k2=k2,
        import_id=import_id,
        user_id=user_id,
        created_count=created_count,
        skipped_count=skipped_count,
        error_count=error_count
    )

    return {
        "status": "done",
        "created_count": created_count,
        "skipped_count": skipped_count,
        "error_count": error_count
    }

13. Приклади банківських виписок і принцип їх обробки

13.1. CSV з колонками DATA_VYP / MFO / AC / OKPO

Приклад структури заголовка:

DATA_VYP;MFO;AC;OKPO;NAME;ND;DATA_D;DK;MFO_KOR;AC_KOR;OKPO_KOR;NAME_KOR;CUR_TAG;CUR_CODE;CUR_RATE;AC_CUR_TAG;AccountCur;SUM_PD_NOM;SUM_PD_EQ;PURPOSE;IN_RST_NO;IN_RST_EQ;OUT_RST_NO;OUT_RST_EQ;DB_SUM_NOM;CR_SUM_NOM;DB_SUM_EQ;CR_SUM_EQ;DAT_OST_OB;DB_IBAN;CR_IBAN;NAME_ACT;OKPO_ACT;Doc_ACT;ResC_ACT;NAME_KOR_ACT;OKPO_KOR_ACT;Doc_KOR_ACT;ResC_KOR_ACT;ADD_INFO;UETR

Характеристики:

Параметр Значення
Тип файлу CSV
Роздільник ;
Кодування Windows-1251 / CP1251
Кількість колонок 41
Ознака дебет/кредит DK або колонки DB_SUM_NOM / CR_SUM_NOM
Призначення платежу PURPOSE
IBAN DB_IBAN / CR_IBAN
Унікальний ідентифікатор UETR

Мапінг:

Поле CSV Поле K2 ERP
DATA_VYP statement_date
MFO own_bank_mfo
AC own_account_number_legacy
OKPO own_edrpou
NAME own_account_name
ND document_number
DATA_D operation_date
DK direction
MFO_KOR counterparty_mfo
AC_KOR counterparty_account_legacy
OKPO_KOR counterparty_edrpou
NAME_KOR counterparty_name
SUM_PD_NOM amount
PURPOSE purpose
DB_SUM_NOM debit_amount
CR_SUM_NOM credit_amount
DB_IBAN debit_iban
CR_IBAN credit_iban
UETR uetr

Принцип обробки:

  1. визначити кодування CP1251;
  2. визначити роздільник `;`;
  3. прочитати заголовок;
  4. перевірити наявність колонок DATA_VYP, MFO, AC, OKPO, ND, DATA_D, DK;
  5. застосувати шаблон CSV_DATA_VYP_MFO_AC_OKPO_V1;
  6. визначити напрям за DK або за ненульовими колонками DB_SUM_NOM / CR_SUM_NOM;
  7. визначити контрагента відносно власного рахунку;
  8. сформувати внутрішні рядки BankStatementImportRow.

Приклад парсера:

def detect_csv_data_vyp(file_meta):
    required_columns = {
        "DATA_VYP",
        "MFO",
        "AC",
        "OKPO",
        "ND",
        "DATA_D",
        "DK",
        "PURPOSE"
    }

    columns = set(file_meta.get("columns", []))

    return required_columns.issubset(columns)


def parse_csv_data_vyp(rows, template):
    result = []

    for row_number, row in enumerate(rows, start=1):
        debit_amount = parse_amount(row.get("DB_SUM_NOM"))
        credit_amount = parse_amount(row.get("CR_SUM_NOM"))

        if debit_amount > 0:
            direction = "DEBIT"
            amount = debit_amount
        elif credit_amount > 0:
            direction = "CREDIT"
            amount = credit_amount
        else:
            direction = detect_direction_by_dk(row.get("DK"))
            amount = parse_amount(row.get("SUM_PD_NOM"))

        result.append({
            "row_number": row_number,
            "operation_date": parse_date(row.get("DATA_D")),
            "document_date": parse_date(row.get("DATA_D")),
            "document_number": row.get("ND"),
            "direction": direction,
            "amount": amount,
            "currency": row.get("AccountCur") or "UAH",
            "counterparty_name": row.get("NAME_KOR"),
            "counterparty_edrpou": row.get("OKPO_KOR"),
            "counterparty_iban": detect_counterparty_iban(row, direction),
            "purpose": row.get("PURPOSE"),
            "uetr": row.get("UETR"),
            "raw_row": row
        })

    return result

13.2. ПриватБанк CSV/DBF/API

Для ПриватБанку потрібно передбачити кілька каналів імпорту:

  • CSV-файл;
  • DBF-файл;
  • API / Автоклієнт.

Очікувані парсери:

  • PrivatbankCsvParser;
  • PrivatbankDbfParser;
  • PrivatbankApiParser.

Принцип обробки CSV/DBF:

  1. визначити тип файлу;
  2. прочитати заголовки або DBF-структуру;
  3. визначити, чи є це шаблоном ПриватБанку;
  4. застосувати відповідний парсер або шаблон мапінгу;
  5. привести дані до BankStatementImportRow.

Принцип обробки API:

  1. користувач налаштовує API-доступ;
  2. система отримує список рахунків;
  3. користувач обирає рахунок;
  4. система запитує виписку за період;
  5. відповідь API перетворюється на внутрішній формат K2 ERP;
  6. дані записуються у preview;
  7. користувач підтверджує імпорт.

13.3. ISO 20022 camt.053 XML

ISO 20022 camt.053 має підтримуватися як стандартизований XML-формат банківської виписки.

Очікуваний парсер:

  • Iso20022Camt053Parser.

Основні вузли для обробки:

XML-вузол Поле K2 ERP
GrpHdr/MsgId Зовнішній ідентифікатор виписки.
GrpHdr/CreDtTm Дата створення виписки.
Stmt/Acct/Id/IBAN IBAN рахунку.
Stmt/Bal Залишки.
Ntry/Amt Сума операції.
Ntry/CdtDbtInd Напрям DEBIT/CREDIT.
Ntry/BookgDt Дата бухгалтерського проведення.
Ntry/ValDt Дата валютування.
Ntry/NtryDtls/TxDtls/RmtInf/Ustrd Призначення платежу.
Ntry/NtryDtls/TxDtls/Refs Референси платежу.
Ntry/NtryDtls/TxDtls/RltdPties Платник / отримувач.

Особливості:

  • один XML може містити кілька виписок;
  • один XML може містити кілька рахунків;
  • призначення платежу може бути структурованим або неструктурованим;
  • дані контрагентів можуть бути вкладені глибоко в XML;
  • необхідно підтримати namespaces XML.

13.4. monobank API

Для monobank потрібно передбачити API-імпорт.

Очікуваний парсер:

  • MonobankApiStatementParser.

Типовий мапінг:

Поле API Поле K2 ERP
id external_transaction_id
time operation_date
description purpose
mcc mcc_code
amount amount
operationAmount operation_amount
currencyCode currency_code
balance balance_after
counterEdrpou counterparty_edrpou
counterIban counterparty_iban

Особливість:

Суми можуть передаватися в мінорних одиницях валюти, наприклад у копійках.

amount = amount_from_api / 100

13.5. iFOBS / клієнт-банк

Для клієнт-банківських систем типу iFOBS потрібно передбачити кілька форматів:

  • DBF;
  • альтернативний DBF;
  • XLS;
  • XML;
  • TXT;
  • SAP-подібні формати.

Очікувані парсери:

  • IFobsDbfParser;
  • IFobsAlternativeDbfParser;
  • IFobsXlsParser;
  • IFobsXmlParser;
  • IFobsTxtParser.

Важливо:

банк ≠ формат
банк = організація
формат = структура файлу
платформа = клієнт-банк

Один банк може мати кілька форматів, а одна клієнт-банківська платформа може використовуватися різними банками.

14. Майстер налаштування імпорту

14.1. Призначення

Майстер налаштування імпорту потрібен для випадків, коли система не змогла автоматично розпізнати формат виписки або користувач хоче створити власний шаблон.

14.2. Кроки майстра

  1. Завантаження файлу.
  2. Вибір типу файлу, якщо система не визначила його автоматично.
  3. Вибір кодування.
  4. Вибір роздільника.
  5. Вибір аркуша для Excel.
  6. Вибір рядка заголовків.
  7. Попередній перегляд перших рядків.
  8. Мапінг колонок.
  9. Налаштування правила суми.
  10. Налаштування правила дебет/кредит.
  11. Налаштування правила контрагента.
  12. Налаштування формату дат.
  13. Тестове розпізнавання.
  14. Збереження шаблону.
  15. Імпорт.

14.3. Мапінг колонок

Поле K2 ERP Колонка у файлі Обов’язковість
Дата операції DATA_D Так
Номер документа ND Так
Сума операції SUM_PD_NOM Так
Дебет DB_SUM_NOM Ні
Кредит CR_SUM_NOM Ні
Контрагент NAME_KOR Так
ЄДРПОУ контрагента OKPO_KOR Ні
IBAN дебету DB_IBAN Ні
IBAN кредиту CR_IBAN Ні
Призначення платежу PURPOSE Так
UETR UETR Ні

14.4. Правила суми

Майстер має підтримувати такі варіанти:

Варіант Приклад
Одна колонка суми зі знаком amount = -1500.00 або 1500.00
Окрема колонка дебету та кредиту debit_amount / credit_amount
Окрема колонка суми та колонка напряму amount + DK
Сума в копійках amount / 100
Сума з комою 1 500,25

14.5. Правила дат

Майстер має підтримувати такі формати дат:

  • DD.MM.YYYY;
  • DD-MM-YYYY;
  • YYYY-MM-DD;
  • DD.MM.YYYY HH:mm:ss;
  • Unix timestamp;
  • ISO datetime.

15. Валідація

15.1. Обов’язкові перевірки

Перевірка Рівень
Немає дати операції ERROR
Немає суми ERROR
Немає напряму платежу ERROR
Немає призначення платежу WARNING
Невалідний IBAN WARNING
Невалідний ЄДРПОУ WARNING
Дублікат операції WARNING / SKIP
Невідома валюта ERROR
Невідомий рахунок K2 ERP ERROR
Період виписки перетинається з уже імпортованим WARNING

15.2. Приклад функції валідації

def validate_statement_rows(k2, rows, account_id):
    errors_count = 0
    warnings_count = 0
    validated_rows = []

    for row in rows:
        messages = []
        status = "OK"

        if not row.get("operation_date"):
            status = "ERROR"
            messages.append("Не заповнена дата операції")

        if not row.get("amount"):
            status = "ERROR"
            messages.append("Не заповнена сума операції")

        if not row.get("direction"):
            status = "ERROR"
            messages.append("Не визначено напрям операції")

        if not row.get("purpose"):
            if status != "ERROR":
                status = "WARNING"
            messages.append("Не заповнено призначення платежу")

        if row.get("counterparty_iban") and not is_valid_iban(row["counterparty_iban"]):
            if status != "ERROR":
                status = "WARNING"
            messages.append("Некоректний IBAN контрагента")

        row["validation_status"] = status
        row["validation_messages"] = messages

        if status == "ERROR":
            errors_count += 1
        elif status == "WARNING":
            warnings_count += 1

        validated_rows.append(row)

    return {
        "rows": validated_rows,
        "errors_count": errors_count,
        "warnings_count": warnings_count
    }

16. Дедублікація

16.1. Принцип

Для кожної операції система формує hash_key.

Якщо у виписці є UETR, він має використовуватись як основа для дедублікації.

Якщо UETR відсутній, ключ формується з комбінації основних полів.

16.2. Правило формування hash_key

def build_hash_key(row, account_iban):
    if row.get("uetr"):
        return sha256_string(
            account_iban + "|" +
            row.get("uetr")
        )

    return sha256_string(
        account_iban + "|" +
        str(row.get("operation_date")) + "|" +
        str(row.get("document_number")) + "|" +
        str(row.get("amount")) + "|" +
        str(row.get("direction")) + "|" +
        str(row.get("counterparty_iban")) + "|" +
        str(row.get("purpose"))
    )

16.3. Поведінка при дублікатах

Ситуація Дія
Операція вже імпортована Позначити як SKIPPED.
Операція є у preview цього ж імпорту Позначити як WARNING.
Операція схожа, але hash_key відрізняється Показати користувачу як можливий дубль.

17. Попередній перегляд

17.1. Мета preview

До створення реальних документів K2 ERP користувач має бачити, що саме буде імпортовано.

17.2. Поля preview

Колонка Опис
Рядок Номер рядка у файлі.
Дата Дата операції.
Документ Номер документа.
Дебет Сума списання.
Кредит Сума надходження.
Контрагент Назва контрагента.
ЄДРПОУ Код контрагента.
IBAN Рахунок контрагента.
Призначення Призначення платежу.
Статус OK / WARNING / ERROR / DUPLICATE.
Повідомлення Опис помилки або попередження.

17.3. Дії користувача у preview

Користувач має мати можливість:

  • переглянути всі рядки;
  • відфільтрувати рядки з помилками;
  • відфільтрувати дублікати;
  • виключити рядок з імпорту;
  • повернутися до мапінгу;
  • підтвердити імпорт;
  • скасувати імпорт.

18. Імпорт у K2 ERP

Після підтвердження користувачем система має:

  1. створити або оновити запис заголовка імпорту;
  2. створити або оновити рядки імпорту;
  3. перевірити дублікати;
  4. створити банківські операції K2 ERP або документи руху коштів;
  5. зв’язати створені документи з рядками імпорту;
  6. зберегти статус кожного рядка;
  7. записати дію в журнал аудиту.

19. UI-вимоги

19.1. Форма імпорту

Форма імпорту має містити:

  • організацію;
  • банківський рахунок;
  • банк;
  • поле вибору файлу;
  • поле вибору шаблону;
  • кнопку “Визначити формат”;
  • кнопку “Налаштувати мапінг”;
  • кнопку “Попередній перегляд”;
  • кнопку “Імпортувати”;
  • статус обробки;
  • повідомлення про помилки.

19.2. Форма шаблонів

Форма шаблонів має дозволяти:

  • створювати шаблон;
  • редагувати шаблон;
  • копіювати шаблон;
  • вимикати шаблон;
  • переглядати JSON-мапінг;
  • тестувати шаблон на файлі;
  • бачити історію змін.

19.3. Форма журналу імпорту

Журнал імпорту має показувати:

  • дату імпорту;
  • користувача;
  • банк;
  • рахунок;
  • файл;
  • шаблон;
  • кількість рядків;
  • кількість помилок;
  • кількість дублікатів;
  • статус імпорту.

20. Права доступу

Роль Права
Accountant Завантаження виписок, preview, запуск імпорту.
Chief Accountant Підтвердження імпорту, створення шаблонів.
Admin Налаштування системних шаблонів і парсерів.
Auditor Перегляд історії імпорту.

21. Логування та аудит

Система має зберігати:

  • користувача, який завантажив файл;
  • дату й час завантаження;
  • назву файлу;
  • хеш файлу;
  • розмір файлу;
  • розпізнаний формат;
  • використаний шаблон;
  • версію парсера;
  • кількість рядків;
  • кількість успішних рядків;
  • кількість рядків з помилками;
  • кількість пропущених дублікатів;
  • оригінальний файл;
  • raw-дані кожного рядка;
  • дату остаточного імпорту;
  • користувача, який підтвердив імпорт.

22. Безпека

22.1. Файли

Модуль має:

  • обмежувати допустимі типи файлів;
  • перевіряти розмір файлу;
  • забороняти виконання макросів Excel;
  • зберігати оригінальний файл у захищеному сховищі;
  • обмежувати доступ до файлів за ролями;
  • не дозволяти виконання вкладених скриптів або формул.

22.2. API-ключі

Для API банків потрібно:

  • зберігати токени в зашифрованому вигляді;
  • не показувати токен після збереження;
  • не логувати секрети;
  • підтримувати відкликання токена;
  • фіксувати дату останнього успішного запиту.

23. MVP першої версії

У першій версії необхідно реалізувати:

Компонент Пріоритет
Generic CSV Mapper P1
Generic DBF Mapper P1
Generic XLSX Mapper P1
ISO 20022 camt.053 Parser P1
CSV-шаблон DATA_VYP/MFO/AC/OKPO P1
ПриватБанк CSV/DBF P1
ПриватБанк API P2
monobank API P2
iFOBS DBF/XLS/XML P2

24. Тестові сценарії

24.1. Імпорт розпізнаного CSV

Дано: CSV-файл з колонками DATA_VYP, MFO, AC, OKPO, DATA_D, DK, PURPOSE.

Очікуваний результат:

  • система визначає формат автоматично;
  • система визначає кодування CP1251;
  • система визначає роздільник `;`;
  • система застосовує відповідний шаблон;
  • система створює preview;
  • система імпортує рядки після підтвердження.

24.2. Імпорт невідомого CSV

Дано: CSV-файл з невідомими колонками.

Очікуваний результат:

  • система не завершується з помилкою;
  • відкривається майстер мапінгу;
  • користувач налаштовує відповідність колонок;
  • система зберігає шаблон;
  • наступний файл такої структури розпізнається автоматично.

24.3. Імпорт camt.053 XML

Дано: XML-файл ISO 20022 camt.053.

Очікуваний результат:

  • система читає рахунок;
  • система читає залишки;
  • система читає операції;
  • система визначає дебет/кредит;
  • система читає призначення платежу;
  • система створює операції K2 ERP.

24.4. Повторний імпорт того самого файлу

Очікуваний результат:

  • система визначає дублікати;
  • дублікати не імпортуються повторно;
  • користувач бачить список пропущених рядків.

24.5. Некоректний IBAN

Очікуваний результат:

  • рядок не блокується повністю, якщо IBAN не обов’язковий;
  • система показує warning;
  • користувач може імпортувати після підтвердження.

25. Критерії приймання

Модуль вважається реалізованим, якщо:

  1. підтримує імпорт CSV, DBF, XLSX, XML camt.053;
  2. автоматично визначає кодування CSV;
  3. автоматично визначає роздільник CSV;
  4. має реєстр Python-парсерів;
  5. має майстер ручного мапінгу;
  6. дозволяє зберігати шаблони мапінгу;
  7. має preview перед імпортом;
  8. виконує валідацію обов’язкових полів;
  9. виконує дедублікацію;
  10. зберігає оригінальний файл;
  11. зберігає raw-дані рядків;
  12. має журнал імпорту;
  13. підтримує мінімум один реальний CSV-шаблон;
  14. підтримує ISO 20022 camt.053;
  15. дозволяє додати новий CSV/XLSX-шаблон без зміни програмного коду;
  16. не створює документи K2 ERP до підтвердження користувачем;
  17. коректно обробляє помилки без аварійного завершення процесу.

26. Обмеження та припущення

  1. Модуль не гарантує автоматичне розпізнавання 100% банківських форматів без первинного налаштування.
  2. Для нового невідомого формату користувач або адміністратор має один раз створити шаблон мапінгу.
  3. API банків реалізуються окремо для кожного банку, оскільки єдиного API для всіх банків немає.
  4. ISO 20022 camt.053 підтримується як найбільш стандартизований XML-формат, але не всі банки можуть надавати його клієнтам.
  5. CSV, DBF та XLSX є лише контейнерами даних, а не єдиним стандартом структури банківської виписки.

27. Подальший розвиток

У наступних версіях модуля можна реалізувати:

  • автоматичне навчання на завантажених шаблонах;
  • бібліотеку шаблонів українських банків;
  • експорт і імпорт шаблонів між інсталяціями K2 ERP;
  • підключення API інших банків;
  • автоматичне звіряння платежів з рахунками, актами та договорами;
  • автоматичне визначення статей руху коштів;
  • автоматичне визначення контрагентів;
  • правила автопроведення банківських операцій;
  • контроль розривів у виписках за періодами.

28. Головний висновок

Модуль має бути не окремим імпортом ПриватБанку, Укргазбанку чи іншого банку, а універсальною платформою імпорту банківських виписок.

Правильна модель:

1. Стандартний формат:
   ISO 20022 camt.053

2. Готові адаптери:
   ПриватБанк, monobank, iFOBS, CSV/DBF конкретних банків

3. Гнучкий мапінг:
   будь-який CSV / DBF / XLSX без зміни коду

4. K2 ERP Python-реалізація:
   форма K2 ERP → Python-скрипт → таблиці preview → підтвердження → документи K2 ERP

Саме така архітектура дозволить K2 ERP підтримувати поточні та майбутні формати банківських виписок українських банків без постійного переписування програмного коду.