Руководство по миграции из QuickBooks в Beancount
Этап 1: Экспорт данных из QuickBooks
Миграция данных за пять лет начинается с выгрузки всех записей из QuickBooks в удобном для использования формате. QuickBooks Desktop и QuickBooks Online имеют разные опции экспорта:
1.1 QuickBooks Desktop – Варианты экспорта
IIF (Intuit Interchange Format): QuickBooks Desktop может экспортировать списки (такие как план счетов, клиенты, поставщики) в текстовые файлы формата .IIF
. В QuickBooks Desktop перейдите в Файл → Утилиты → Экспорт → Списки в IIF (File → Utilities → Export → Lists to IIF), затем выберите нужные списки (например, План счетов, Клиенты, Поставщики). В результате вы получите текстовый файл, содержащий названия счетов, их типы и данные из списков. IIF — это проприетарный, но текстовый формат, который относительно легко разобрать. Используйте его, чтобы получить ваш План счетов и списки контактов для дальнейшего использования в Beancount.
Главная книга/Журнал через CSV: Для экспорта транзакций QuickBooks Desktop не предоставляет полного экспорта в один клик, но можно использовать отчёты. Рекомендуемый метод — экспорт Главного журнала (всех транзакций) за желаемый период. В QuickBooks Desktop откройте Отчёты → Бухгалтер и налоги → Журнал (Reports → Accountant & Taxes → Journal), установите Даты с самой ранней транзакции до сегодняшнего дня и нажмите Экспорт → Excel. Сохраните результат как CSV, предварительно удалив все заголовки/подвалы отчёта и пустые столбцы. Убедитесь, что числовые данные чистые: содержат центы (например, 3.00
, а не 3
), без лишних кавычек, символов валют или двойных минусов в CSV. CSV-файл должен иметь столбцы, такие как Дата, № транз., Имя, Счёт, Заметка, Дебет, Кредит, Остаток (или один столбец "Сумма" в зависимости от формата отчёта).
Совет: QuickBooks Desktop 2015+ также может экспортировать транзакции через диалоговое окно Найти (Find). Используйте Правка → Найти → Расширенный поиск (Edit → Find → Advanced), установите диапазон дат на пять лет, а затем экспортируйте результаты в CSV. Предупреждение: Некоторые версии ограничивают экспорт 32 768 строками. Если у вас очень большой объём данных, экспортируйте по годам (или меньшими частями), чтобы избежать усечения, а затем объедините их. Убедитесь, что диапазоны дат не пересекаются, чтобы избежать дубликатов.
Другие форматы (QBO/QFX/QIF): QuickBooks Desktop может импортировать банковские транзакции через файлы .QBO
(Web Connect) или .QFX/.OFX
, но для экспорта из QuickBooks они обычно не используются. Если ваша цель — извлечь только банковские т ранзакции, они у вас уже могут быть в формате QBO/OFX от вашего банка. Однако для полного экспорта главной книги придерживайтесь IIF и CSV. QuickBooks Desktop не может напрямую экспортировать в QIF (Quicken Interchange Format) без сторонних инструментов. Если вы найдёте способ получить QIF, учтите, что некоторые инструменты для учёта (старые версии Ledger 2.x) могли читать QIF, но в нашем процессе лучше работать с CSV.
1.2 QuickBooks Online – Варианты экспорта
Встроенный экспорт в Excel/CSV: QuickBooks Online (QBO) предоставляет инструмент Экспорт данных. Перейдите в Настройки ⚙ → Инструменты → Экспорт данных (Settings ⚙ → Tools → Export Data). В диалоговом окне экспорта используйте вкладку Отчёты для выбора данных (например, Главная книга или Список транзакций) и вкладку Списки для списков (план счетов и т.д.), выберите Все даты и экспортируйте в Excel. QuickBooks Online загрузит ZIP-архив, содержащий несколько файлов Excel для выбранных отчётов и списков (например, Отчёт о прибылях и убытках, Балансовый отчёт, Главная книга, Клиенты, Поставщики, План счетов и т.д.). Затем вы можете преобразовать эти файлы Excel в CSV для обработки.
Отчёт о детализации транзакций: Если стандартный экспорт QBO не включает единый файл Главной книги, вы можете вручную создать детализированный отчёт:
- Перейдите в Отчёты и найдите Детализация транзакций по счетам (Transaction Detail by Account) или Главная книга (General Ledger) в некоторых версиях QBO.
- Установите Отчётный период на полный пятилетний диапазон.
- В опциях отчёта установите Группировать по = Нет (чтобы отобразить отдельные транзакции без промежуточных итогов).
- Настройте столбцы, чтобы включить как минимум: Дату, Тип транзакции, Номер, Имя (Получатель/Клиент), Заметка/Описание, Счёт, Дебет, Кредит (или один столбец "Сумма") и Остаток. Включите класс или местоположение, если они используются.
- Сформируйте отчёт, а затем Экспортируйте в Excel.
Это даст детализированную главную книгу всех транзакций. Сохраните её как CSV. Каждая строка будет представлять одну проводку транзакции. Позже вам нужно будет сгруппировать строки по транзакциям для конвертации.
План счетов и другие списки: QuickBooks Online может экспортировать план счетов через Учёт → План счетов → Пакетные действия → Экспорт в Excel (Accounting → Chart of Accounts → Batch Actions → Export to Excel). Сделайте это, чтобы получить названия и типы счетов. Аналогично, экспортируйте Клиентов, Поставщиков и т.д., если хотите перенести имена для метаданных.
QuickBooks Online API (Необязательно): Для программного подхода Intuit предоставляет REST API для данных QBO. Продвинутые пользователи могут создать приложение QuickBooks Online (требуется аккаунт разработчика) и использовать API для получения данных в формате JSON. Например, вы можете запросить эндпоинт Account
для плана счетов и эндпоинты отчётов JournalEntry
или GeneralLedger
для транзакций. Существуют Python SDK, такие как python-quickbooks
, которые являются обёртками над API. Однако использование API включает в себя аутентификацию по OAuth и является излишним для одноразовой миграции, если вы не предпочит аете автоматизацию. В большинстве случаев ручной экспорт в CSV/Excel проще и менее подвержен ошибкам.
Этап 2: Трансформация и очистка данных
Когда у вас есть данные из QuickBooks в формате CSV (и/или IIF), следующий шаг — преобразовать их в текстовый формат главной книги Beancount. Это включает разбор экспортированных файлов, сопоставление счетов QuickBooks с планом счетов Beancount и форматирование транзакций в синтаксисе Beancount.
2.1 Разбор экспортов из QuickBooks с помощью Python
Использование Python обеспечит точность и воспроизводимость трансформации. Мы наметим скрипты для двух ключевых задач: импорт плана сче тов и конвертация транзакций.
Импорт и сопоставление счетов: Крайне важно настроить ваши счета в Beancount перед добавлением транзакций. Счета QuickBooks имеют типы (Банк, Дебиторская задолженность, Расходы и т.д.), которые мы сопоставим с иерархией Beancount (Активы, Обязательства, Доходы, Расходы и т.д.). Например, мы можем использовать такое сопоставление:
# Сопоставление типа счёта QuickBooks с корневой категорией Beancount
AccountTypeMap = {
'BANK': 'Assets',
'CCARD': 'Liabilities',
'AR': 'Assets', # Дебиторская задолженность как актив
'AP': 'Liabilities', # Кредиторская задолженность как обязательство
'FIXASSET': 'Assets',
'OASSET': 'Assets', # Прочие активы
'OCASSET': 'Assets', # Прочие оборотные активы
'LTLIAB': 'Liabilities', # Долгосрочные обязательства
'OCLIAB': 'Liabilities', # Прочие текущие обязательства
'EQUITY': 'Equity',
'INC': 'Income',
'EXP': 'Expenses',
'EXINC': 'Income', # Прочие доходы
'EXEXP': 'Expenses', # Прочие расходы
}
Используя экспорт IIF из QuickBooks Desktop или CSV-файл со списком счетов из QBO, мы получаем имя и тип каждого счёта. Затем:
-
Создайте имена счетов Beancount: QuickBooks иногда использует двоеточия (
:
) в именах счетов для обозначения субсчетов (например, "Current Assets:Checking"). Beancount использует ту же нотацию с двоеточием для иерархии. Часто можно использовать имя напрямую. Если имена счетов QuickBooks не начинаются с категории, добавьте сопоставленную категорию в начало. Например, счёт QuickBooks типаBANK
с названием "Checking" станетAssets:Checking
в Beancount. СчётEXP
(расход) "Meals" станетExpenses:Meals
и т.д. -
Обеспечьте корректность именования: Удалите или замените любые символы, которые могут сбить Beancount с толку. QuickBooks допускает символы вроде
&
или/
в именах. Разумно вырезать или заменить специальные символы (например, заменить&
наand
, удалить слэши или пробелы). Также убедитесь, что все имена счетов уникальны после трансформации – QuickBooks мог позволять одинаковые имена субсчетов у разных родительских счетов, что нормально, но в Beancount полное имя (с родителями) должно быть уникальным. При необходимости переименуйте или добавьте квалификатор для их различения. -
Выведите открытия счетов: В Beancount каждый используемый счёт должен быть открыт с помощью директивы
open
. Вы можете выбрать дату до вашей первой транзакции (например, если вы мигрируете данные за 2019–2023 годы, используйте2018-12-31
или даже более раннюю дату для всех открытий). Скрипт запишет строки вида:2018-12-31 open Assets:Checking USD
2018-12-31 open Expenses:Meals USD
для каждого счёта (предполагая, что основная валюта — USD). Используйте соответствующую валюту для каждого счёта (см. заметки о мультивалютности ниже).
Конвертация транзакций: Основная задача — преобразовать экспорт транзакций QuickBooks (CSV) в записи Beancount. Каждая транзакция QuickBooks (счёт-фактура, счёт, чек, журнальная запись и т.д.) может иметь несколько проводок (строк), которые необходимо собрать в одну транзакцию Beancount.
Мы будем использовать CSV-ридер Python для итерации по экспортированным строкам и накопления проводок:
import csv
from collections import defaultdict
# Чтение всех строк из CSV-файла журнала QuickBooks
rows = []
with open('quickbooks_exported_journal.csv', 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for line in reader:
rows.append(line)
# Группировка строк по транзакциям (предполагая, что 'Trans #' идентифицирует транзакции)
transactions = defaultdict(list)
for line in rows:
trans_id = line.get('Trans #') or line.get('Transaction ID') or line.get('Num')
transactions[trans_id].append(line)
Теперь transactions
— это словарь, где каждый ключ — это ID/номер транзакции, а значение — список проводок для этой транзакции. Далее мы конвертируем каждую группу в формат Beancount:
def format_date(qb_date):
# Даты в QuickBooks могут быть в формате "12/31/2019"
m, d, y = qb_date.split('/')
return f"{y}-{int(m):02d}-{int(d):02d}"
output_lines = []
for trans_id, splits in transactions.items():
# Сортировка проводок по порядку строк, если необходимо (обычно они уже упорядочены)
splits = sorted(splits, key=lambda x: x.get('Line') or 0)
first = splits[0]
date = format_date(first['Date'])
payee = first.get('Name', "").strip()
memo = first.get('Memo', "").strip()
# Заголовок транзакции
output_lines.append(f"{date} * \"{payee}\" \"{memo}\"")
if first.get('Num'): # включаем номер ссылки, если доступен
output_lines.append(f" number: \"{first['Num']}\"")
# Цикл по каждой проводке/постингу
for split in splits:
acct_name = split['Account'].strip()
# Сопоставляем имя счёта QuickBooks со счётом Beancount (используя предыдущее сопоставление)
beancount_acct = account_map.get(acct_name, acct_name)
# Определяем сумму со знаком:
amount = split.get('Amount') or ""
debit = split.get('Debit') or ""
credit = split.get('Credit') or ""
if amount:
# Некоторые экспорты имеют один столбец Amount (отрицательный для кредитов)
amt_str = amount
else:
# Если отдельные столбцы Debit/Credit
amt_str = debit if debit else f"-{credit}"
# Для безопасности удаляем все запятые в числах
amt_str = amt_str.replace(",", "")
# Добавляем валюту
currency = split.get('Currency') or "USD"
amt_str = f"{amt_str} {currency}"
# Заметка/описание для проводки
line_memo = split.get('Memo', "").strip()
comment = f" ; {line_memo}" if line_memo else ""
output_lines.append(f" {beancount_acct:<40} {amt_str}{comment}")
# Конец транзакции – пустая строка
output_lines.append("")
Эта логика скрипта выполняет следующее:
-
Форматирует дату в YYYY-MM-DD для Beancount.
-
Использует получателя (Name) и заметку (Memo) для описания транзакции. Например:
2020-05-01 * "ACME Corp" "Оплата счёта-фактуры"
(Если получателя нет, можно использовать Тип транзакции из QuickBooks или оставить кавычки пустыми). -
Добавляет метаданные
number
, если есть номер ссылки (№ чека, № счёта-фактуры и т.д.). -
Итерирует по каждой стр оке проводки:
- Сопоставляет имя счёта QuickBooks со счётом Beancount, используя словарь
account_map
(заполненный на шаге с планом счетов). - Определяет сумму. В зависимости от вашего экспорта, у вас может быть один столбец Сумма (с положительными/отрицательными значениями) или отдельные столбцы Дебет и Кредит. Приведённый выше код обрабатывает оба случая. Он гарантирует, что кредиты представляются как отрицательные суммы для Beancount (так как в Beancount для каждой проводки используется одно число со знаком).
- Прикрепляет валюту (предполагая USD, если не указан другой столбец с валютой).
- Записывает строку проводки Beancount со счётом, суммой и комментарием с заметкой из строки. Например:
Assets:Checking 500.00 USD ; Депозит
Income:Sales -500.00 USD ; Депозит
Это отражает депозит в $500 (с Доходов на Расчётный счёт).
- Сопоставляет имя счёта QuickBooks со счётом Beancount, используя словарь
-
После перечисления всех проводок пустая строка разделяет транзакции.
Обработка мультивалютности: Если ваши данные в QuickBooks включают несколько валют, указывайте код валюты в каждой проводке (как показано выше). Убедитесь, что счета в иностранных валютах открыты с этой валютой. Например, если у вас есть банковский счёт в EUR, вы должны вывести open Assets:Bank:Checking EUR
, и транзакции на этом счёте будут использовать EUR. Beancount поддерживает мультивалютные главные книги и будет отслеживать неявные конвертации, но вам может понадобиться добавить записи о ценах для курсов обмена, если вы хотите конвертировать в базовую валюту в отчётах. Также рекомендуется объявить вашу основную операционную валюту вверху файла Beancount (например, option "operating_currency" "USD"
).
Запуск конвертации: Сохраните скрипт Python (например, как qb_to_beancount.py
) и запустите его на ваших экспортированных файлах. Он должен создать файл .beancount
, содержащий все счета и транзакции.
2.2 Обработка крайних случаев и очистка данных
Во время трансформации помните об этих распространённых подводных камнях и способах их решения:
-
Несоответствия в названиях счетов: В QuickBooks могут быть имена счетов, которые конфликтуют с иерархическими именами Beancount. Например, в QuickBooks могут быть два разных родительских счёта, у каждого из которых есть субсчёт с названием "Страхование". В Beancount
Expenses:Insurance
должно быть уникальным. Решите это, переименовав один из них (например, "Страхование-Автомобиль" против "Страхование-Здоровье") перед экспортом или сопоставьте их с уникальными счетами Beancount в вашем скрипте. Последовательные соглашения об именах (без специальных символов и с использованием иерархии) сэкономят вам головную боль. При необходимости используйте подход с файлом пересопоставления: ведите CSV или словарь "старое имя → новое имя Beancount" и применяйте его во время конвертации (наш пример кода используетaccount_map
и мог бы загружать переопределения из файла). -
Даты и форматы: Убедитесь, что все даты отформатированы последовательно. Приведённый выше скрипт нормализует M/D/Y в формат ISO. Также следите за проблемами с финансовым и календарным годом, если ваш пятилетний период пересекает конец года. Beancount не волнуют границы финансового года, но позже вы можете захотеть разделить файлы по годам для удобства.
-
Числовая точность: QuickBooks обрабатывает валюту с центами, поэтому работа в центах обычно подходит. Все суммы в идеале должны иметь два десятичных знака в CSV. Если какие-то суммы превратились в целые числа (без десятичной части) или содержат запятые/скобки (для отрицательных чисел), очистите их в скрипте (удалите запятые, преобразуйте
(100.00)
в-100.00
и т.д.). Экспорт в CSV, если он выполнен правильно (согласно инструкциям), должен был уже избежать этих проблем с форматированием. -
Отрицательные суммы и знаки: Отчёты QuickBooks иногда показывают отрицательные числа как
-100.00
,(100.00)
или даже--100.00
в некоторых экспортах в Excel. Шаг очистки должен справиться с этим. Убедитесь, что дебеты и кредиты каждой транзакции в сумме дают ноль. Beancount будет это проверять (если не сбалансировано, он выдаст ошибку при импорте). -
Дубликаты транзакций: Если вам пришлось экспортировать т ранзакции частями (например, по годам или по счетам), будьте осторожны при их объединении, чтобы избежать пересечений. Проверьте, что первая транзакция года не является также последней из предыдущей партии и т.д. Легко случайно продублировать несколько транзакций на границах. Если вы подозреваете дубликаты, вы можете отсортировать итоговые записи Beancount по дате и поискать идентичные записи, или использовать уникальные теги транзакций Beancount для их отлова. Одна из стратегий — включить номера транзакций QuickBooks в метаданные (например, использовать
Trans #
или номер счёта-фактуры как тегtxn
или метаданныеquickbooks_id
), а затем убедиться в отсутствии дубликатов этих ID. -
Несбалансированные проводки / Временные счета: В QuickBooks могут быть странные случаи, например, транзакция с дисбалансом, который QuickBooks автоматически скорректировал на счёт "Начальный капитал" или "Нераспределённая прибыль". Например, при настройке начальных остатков счетов QuickBooks часто проводит разницы на счёт Капитала. Они появятся в экспортированных транзакциях. Beancount потребует явной балансировк и. Вам может понадобиться ввести счёт Капитала для начальных остатков (обычно
Equity:Opening-Balances
), чтобы отразить логику QuickBooks. Хорошей практикой является создание записи о начальных остатках в первый день вашей главной книги, которая устанавливает стартовые балансы всех счетов (см. Этап 5). -
Крайние случаи с мультивалютностью: При использовании нескольких валют экспорт из QuickBooks может перечислять все суммы в домашней валюте или в их родной валюте. В идеале, получите данные в родной валюте для каждого счёта (отчёты QuickBooks Online обычно так и делают). В Beancount каждая проводка несёт в себе валюту. Если QuickBooks предоставил курсы обмена или конвертацию в домашнюю валюту, вы можете проигнорировать их и полагаться на записи о ценах в Beancount. Если QuickBooks не экспортировал курсы обмена, вы можете захотеть вручную добавить записи о ценах (например, используя директиву
price
в Beancount) для ключевых дат, чтобы соответствовать оценке. Однако для базовой целостности главной книги достаточно, чтобы транзакции сходились в своих исходных валютах – нереализованные прибыли/убытки не нужно явно записыв ать, если вы не хотите получить те же отчёты. -
Дебиторская / Кредиторская задолженность: QuickBooks отслеживает детали счетов-фактур и счетов (сроки оплаты, статус оплаты и т.д.), которые не будут полностью перенесены в простую главную книгу. Вы получите транзакции по дебиторской и кредиторской задолженности (счета-фактуры увеличивают ДЗ, платежи уменьшают ДЗ и т.д.), но не документы счетов-фактур или балансы клиентов по счетам. В результате после миграции вы должны проверить, что балансы ваших счетов ДЗ и КЗ в Beancount равны открытым остаткам клиентов/поставщиков в QuickBooks. Если вам нужно отслеживать счета-фактуры, вы можете использовать метаданные Beancount (например, включить тег
invoice
или ссылку). Номера счетов-фактур из QuickBooks должны были перейти в поляNum
илиMemo
– наш скрипт сохраняетNum
какnumber: "..."
в метаданных транзакции. -
Неактивные или закрытые счета: Экспорт IIF может включать неактивные счета (если вы выбрали их включение). Их можно импортировать (у них просто не будет транзакций и будет нулевой баланс, если они действительно неактивны). Вы можете пометить их как закрытые в Beancount после даты последней транзакции с помощью директивы
close
. Это поддерживает порядок в вашей главной книге. Например:2023-12-31 close Expenses:OldAccount ; закрыт после миграции
Это необязательно и в основном для чистоты.
Тщательно очистив и сопоставив данные, как описано выше, вы получите файл главной книги Beancount, который структурно отражает ваши данные из QuickBooks. Следующий шаг — убедиться, что он также численно отражает QuickBooks.
Этап 3: Проверка и сверка данных
Проверка — это критически важный этап в миграции бухгалтерских данных. Нам нужно убедиться, что главная книга Beancount совпадает с книгами QuickBooks до копейки. Для этого можно использовать несколько стратегий и инструментов: