راهنمای جامع مهاجرت از QuickBooks به Beancount
مرحله ۱: استخراج دادهها از QuickBooks
مهاجرت دادههای پنج ساله با خارج کردن تمام سوابق QuickBooks در یک فرمت قابل استفاده آغاز میشود. QuickBooks Desktop و QuickBooks Online گزینههای خروجیگیری متفاوتی دارند:
۱.۱ QuickBooks Desktop – گزینههای خروجیگیری
IIF (Intuit Interchange Format): نرمافزار QuickBooks Desktop میتواند لیستها (مانند سرفصل حسابها، مشتریان، فروشندگان) را به فایلهای متنی .IIF
خروجی بگیرد. در QuickBooks Desktop، به مسیر File → Utilities → Export → Lists to IIF بروید، سپس لیستهای مورد نیاز خود (مانند Chart of Accounts، Customers، Vendors) را انتخاب کنید. این کار یک فایل متنی تولید میکند که شامل نام حسابها، انواع آنها و دادههای لیست است. IIF یک فرمت اختصاصی اما مبتنی بر متن ساده است که تجزیه (parse) آن نسبتاً آسان است. از آن برای استخراج سرفصل حسابها (Chart of Accounts) و لیست مخاطبین خود برای ارجاع در Beancount استفاده کنید.
دفتر کل/دفتر روزنامه از طریق CSV: برای دادههای تراکنش، QuickBooks Desktop یک خروجی کامل با یک کلیک ارائه نمیدهد، اما میتوانید از گزارشها استفاده کنید. روش پیشنهادی، خروجی گرفتن از دفتر روزنامه عمومی (General Journal) (شامل تمام تراکنشها) در بازه زمانی مورد نظر است. در QuickBooks Desktop، به مسیر Reports → Accountant & Taxes → Journal بروید، تاریخها را از اولین تراکنش تا امروز تنظیم کنید و روی Export → Excel کلیک کنید. پس از حذف هرگونه سرصفحه/پاصفحه گزارش و ستونهای خالی، نتیجه را به صورت CSV ذخیره کنید. اطمینان حاصل کنید که دادههای عددی تمیز هستند: شامل سنت (مثلاً 3.00
نه 3
)، بدون علامت نقل قول اضافی، و بدون نماد ارز یا منفیهای دوگانه در CSV باشند. فایل CSV باید ستونهایی مانند Date, Trans #, Name, Account, Memo, Debit, Credit, Balance (یا یک ستون Amount واحد بسته به فرمت گزارش) داشته باشد.
نکته: 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 کار کنیم.
۱.۲ QuickBooks Online – گزینههای خروجیگیری
خروجی داخلی Excel/CSV: نسخه آنلاین QuickBooks (QBO) ابزاری به نام Export Data ارائه میدهد. به Settings ⚙ → Tools → Export Data بروید. در کادر محاورهای خروجی، از تب Reports برای انتخاب دادهها (مانند General Ledger یا Transaction List) و از تب Lists برای لیستها (سرفصل حسابها و غیره) استفاده کنید، All dates را انتخاب کرده و به Excel خروجی بگیرید. QuickBooks Online یک فایل ZIP حاوی چندین فایل Excel برای گزارشها و لیستهای انتخاب شده (به عنوان مثال، سود و زیان، ترازنامه، دفتر کل، مشتریان، فروشندگان، سرفصل حسابها و غیره) دانلود میکند. سپس میتوانید این فایلهای Excel را برای پردازش به CSV تبدیل کنید.
گزارش جزئیات تراکنش: اگر خروجی پیشفرض QBO شامل یک فایل دفتر کل واحد نباشد، میتوانید به صورت دستی یک گزارش دقیق تهیه کنید:
- به Reports بروید و Transaction Detail by Account (یا General Ledger در برخی نسخههای QBO) را پیدا کنید.
- Report period را روی بازه کامل پنج ساله تنظیم کنید.
- زیر گزینههای گزارش، Group by = None را تنظیم کنید (تا تراکنشهای فردی بدون جمعهای فرعی لیست شوند).
- ستونها را سفارشی کنید تا حداقل شامل این موارد باشند: Date، Transaction Type، Number، Name (Payee/Customer)، Memo/Description، Account، Debit، Credit (یا یک ستون Amount واحد) و Balance. در صورت استفاده، هرگونه class یا location را نیز شامل کنید.
- گزارش را اجرا کرده و سپس Export to Excel را بزنید.
این کار یک دفتر کل دقیق از تمام تراکنشها را به دست میدهد. آن را به صورت CSV ذخیره کنید. هر خط نشاندهنده یک آرتیکل (پستینگ) از یک تراکنش است. بعداً برای تبدیل، باید خطوط را بر اساس تراکنش گروهبندی کنید.
سرفصل حسابها و لیستهای دیگر: در QuickBooks Online میتوانید سرفصل حسابها را از طریق Accounting → Chart of Accounts → Batch Actions → Export to Excel خروجی بگیرید. این کار را برای دریافت نامها و انواع حسابها انجام دهید. به همین ترتیب، اگر میخواهید نامها را برای فراداده (metadata) حفظ کنید، لیست مشتریان، فروشندگان و غیره را نیز خروجی بگیرید.
API QuickBooks Online (اختیاری): برای یک رویکرد برنامهنویسی، Intuit یک REST API برای دادههای QBO ارائه میدهد. کاربران پیشرفته میتوانند یک اپلیکیشن QuickBooks Online ایجاد کنند (نیاز به حساب توسعهدهنده دارد) و از API برای دریافت دادهها در فرمت JSON استفاده کنند. به عنوان مثال، میتوانید از نقطه پایانی (endpoint) Account
برای سرفصل حسابها و از نقاط پایانی گزارش JournalEntry
یا GeneralLedger
برای تراکنشها کوئری بگیرید. SDKهای پایتون مانند python-quickbooks
وجود دارند که API را در خود جای دادهاند. با این حال، استفاده از API شامل احراز هویت OAuth است و برای یک مهاجرت یکباره، مگر اینکه اتوماسیون را ترجیح دهید، بیش از حد پیچیده است. برای اکثر موارد، خروجی دستی به CSV/Excel سادهتر و کمتر مستعد خطا است.
مرحله ۲: تبدیل و پاکسازی دادهها
هنگامی که دادههای QuickBooks را در فرمت CSV (و/یا IIF) در اختیار دارید، مرحله بعدی تبدیل آن به فرمت دفتر کل متنی ساده Beancount است. این شامل تجزیه خروجیها، نگاشت حسابهای QuickBooks به سرفصل حسابهای Beancount و فرمتبندی تراکنشها با سینتکس 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 کوییکبوکس دسکتاپ یا CSV لیست حسابهای QBO، نام و نوع هر حساب را بازیابی میکنیم. سپس:
-
ایجاد نام حسابهای Beancount: کوییکبوکس گاهی از علامت دو نقطه (
:
) در نام حسابها برای نشان دادن حسابهای فرعی استفاده میکند (مثلاً “Current Assets:Checking”). Beancount از همین علامت دو نقطه برای سلسله مراتب استفاده میکند. اغلب میتوانید نام را مستقیماً استفاده کنید. اگر نام حسابهای کوییکبوکس با یک دستهبندی شروع نمیشود، دستهبندی نگاشت شده را به ابتدای آن اضافه کنید. برای مثال، یک حساب کوییکبوکس از نوعBANK
به نام "Checking" در Beancount بهAssets:Checking
تبدیل میشود. یک حسابEXP
(هزینه) به نام "Meals" بهExpenses:Meals
تبدیل میشود و غیره. -
اطمینان از نامگذاری معتبر: کاراکترهایی که ممکن است Beancount را گیج کنند حذف یا جایگزین کنید. کوییکبوکس کاراکترهایی مانند
&
یا/
را در نامها مجاز میداند. عاقلانه است که کاراکترهای خاص را حذف یا جایگزین کنید (مثلاً&
را باand
جایگزین کنید، اسلشها یا فاصلهها را حذف کنید). همچنین، اطمینان حاصل کنید که تمام نامهای حساب پس از تبدیل منحصر به فرد هستند – ممکن است کوییکبوکس اجازه دهد نام حساب فرعی یکسانی زیر والدین مختلف وجود داشته باشد که مشکلی ندارد، اما در Beancount نام کامل (با والدین) باید منحصر به فرد باشد. در صورت لزوم، برای تمایز، نام را تغییر دهید یا یک شناسه به آن اضافه کنید. -
خروجی گرفتن افتتاح حسابها: در Beancount، هر حسابی که استفاده میشود باید با دستور
open
افتتاح شود. میتوانید تاریخی قبل از اولین تراکنش خود انتخاب کنید (مثلاً اگر دادههای ۲۰۱۹-۲۰۲۳ را منتقل میکنید، از2018-12-31
یا تاریخی حتی زودتر برای همه افتتاحها استفاده کنید). اسکریپت خطوطی مانند این را خواهد نوشت:2018-12-31 open Assets:Checking USD
2018-12-31 open Expenses:Meals USD
برای هر حساب (با فرض اینکه USD ارز اصلی است). از ارز مناسب برای هر حساب استفاده کنید (به یادداشتهای چند ارزی در ادامه مراجعه کنید).
تبدیل تراکنش: چالش اصلی تبدیل خروجی تراکنشهای QuickBooks (CSV) به ورودیهای Beancount است. هر تراکنش QuickBooks (فاکتور، قبض، چک، سند روزنامه و غیره) میتواند چندین آرتیکل (خط) داشته باشد که باید در یک تراکنش Beancount جمعآوری شوند.
ما از خواننده CSV پایتون برای پیمایش خطوط خروجی گرفته شده و جمعآوری آرتیکلها استفاده خواهیم کرد:
import csv
from collections import defaultdict
# خواندن تمام خطوط از فایل CSV دفتر روزنامه کوییکبوکس
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
یک دیکشنری است که هر کلید آن یک شناسه/شماره تراکنش است و مقدار آن لیستی از آرتیکلهای آن تراکنش است. در ادامه، هر گروه را به فرمت Beancount تبدیل میکنیم:
def format_date(qb_date):
# تاریخهای کوییکبوکس ممکن است مانند "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()
# نگاشت نام حساب کوییکبوکس به حساب بینکانت (با استفاده از نگاشت قبلی)
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:
# اگر ستونهای بدهکار/بستانکار جدا باشند
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("")
منطق این اسکریپت کارهای زیر را انجام میدهد:
- تاریخ را برای Beancount به فرمت YYYY-MM-DD تبدیل میکند.
- از طرف حساب (Name) و شرح (Memo) برای روایت تراکنش استفاده میکند. به عنوان مثال:
2020-05-01 * "ACME Corp" "Invoice payment"
(اگر طرف حسابی وجود نداشته باشد، میتوانید از نوع تراکنش کوییکبوکس استفاده کنید یا طرف حساب را خالی بگذارید). - اگر شماره مرجعی وجود داشته باشد (شماره چک، شماره فاکتور و غیره)، یک فراداده
number
اضافه میکند. - روی هر خط آرتیکل تکرار میکند:
- نام حساب QuickBooks را با استفاده از یک دیکشنری
account_map
(که از مرحله سرفصل حسابها پر شده) به حساب Beancount نگاشت میکند. - مبلغ را تعیین میکند. بسته به خروجی شما، ممکن است یک ستون Amount واحد (با مقادیر مثبت/منفی) یا ستونهای Debit و Credit جداگانه داشته باشید. کد بالا هر دو حالت را مدیریت میکند. این کد تضمین میکند که مبالغ بستانکار به عنوان مقادیر منفی نمایش داده شوند (زیرا در Beancount، برای هر پستینگ از یک عدد با علامت استفاده میشود).
- ارز را ضمیمه میکند (با فرض USD مگر اینکه ستون ارز دیگری وجود داشته باشد).
- خط پستینگ Beancount را با حساب، مبلغ و یک کامنت با شرح خط مینویسد. به عنوان مثال:
Assets:Checking 500.00 USD ; Deposit
Income:Sales -500.00 USD ; Deposit
این نشاندهنده یک واریز ۵۰۰ دلاری است (از درآمد به حساب جاری).
- نام حساب QuickBooks را با استفاده از یک دیکشنری
- پس از لیست کردن تمام آرتیکلها، یک خط خالی تراکنش را جدا میکند.
مدیریت چند ارزی: اگر دادههای QuickBooks شما شامل چندین ارز باشد، کد ارز را در هر پستینگ (همانطور که در بالا نشان داده شد) درج کنید. اطمینان حاصل کنید که حسابهایی که به ارزهای خارجی هستند با همان ارز افتتاح شوند. به عنوان مثال، اگر یک حساب بانکی به یورو (EUR) دارید، باید open Assets:Bank:Checking EUR
را خروجی بگیرید و تراکنشهای آن حساب از EUR استفاده خواهند کرد. Beancount از دفترهای کل چند ارزی پشتیبانی میکند و تبدیلهای ضمنی را ردیابی خواهد کرد، اما اگر میخواهید در گزارشها تبدیل به یک ارز پایه داشته باشید، ممکن است نیاز به اضافه کردن ورودیهای قیمت برای نرخهای ارز داشته باشید. همچنین توصیه میشود که ارز عملیاتی اصلی خود را در بالای فایل Beancount اعلام کنید (مثلاً option "operating_currency" "USD"
).
اجرای تبدیل: اسکریپت پایتون را (به عنوان مثال، با نام qb_to_beancount.py
) ذخیره کرده و آن را بر روی فایلهای خروجی گرفته شده خود اجرا کنید. این باید یک فایل .beancount
حاوی تمام حسابها و تراکنشها تولید کند.