Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/extraScripts/migration/holoo2hesabix/docs/ACCOUNTING_MIGRATION_PLAN.md
Babak Alizadeh a5875e7a3a Release Holoo2Hesabix 1.1.0 with production-ready accounting migration.
Harden Holoo-to-Hesabix document partition/mapping, sample E2E tooling, remove hardcoded SQL credentials from scripts, fix income AR account 10401, and publish Setup MSI 1.1.0.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 15:56:40 +03:30

39 KiB
Raw Permalink Blame History

طرح فنی انتقال حسابداری هلو → حسابیکس

وضعیت: در حال پیاده‌سازی
آخرین پیشرفت: E2E biz 6823 — نمونه همه ماژول‌ها OK؛ انتقال کامل در جریان (run-full-e2e.ps1)؛ 801→40001؛ EI بدون FACTURE/Check؛ بدون dump تک‌بانک/تک‌صندوق؛ چک API path اصلاح؛ درآمد شخص 10401.

پیشرفت پیاده‌سازی

فاز وضعیت شواهد
۰ سنجش انجام‌شده scripts/audit-partition.ps1 — روی Holoo1: MANUAL=4، excluded facture-linked=538
۱ پارتیشن انجام‌شده ReadManualJournalsInRange + CountSql با NOT EXISTS FACTURE؛ preflight گزارش overlap
۲ کاتالوگ انجام‌شده mapper بدون 70401/FirstOrDefault؛ لینک مستقیم بانک و صندوق؛ وام/هزینه اختصاصی؛ invariants سبز
۳ پروفایل UI انجام‌شده گرید با ستون Override قابل ویرایش؛ قفل پروفایل؛ انتقال اسناد بدون قفل متوقف
۴–۶ انتقال هسته + E2E افتتاحیه افتتاحیه Holoo1→biz6823 ثبت و پست شد (۱۲۶ خط، متوازن)؛ Abort روی Block
۷–۸ اثبات جزئی→قوی‌تر BalanceProofService + compare-opening-balance.ps1؛ مقایسه خالص Col↔کد حسابیکس

هدف محصول: هر سند هلو که اثر دفتری دارد، دقیقاً یک‌بار، با ماهیت درست، متوازن، و قابل ردیابی به Sanad_Code هلو، در حسابیکس بنشیند. اختلاف تراز فقط وقتی پذیرفته است که منبعش خود هلو باشد و در گزارش مهاجرت با کد سند توضیح داده شده باشد.


۱. قرارداد صحت (غیرقابل مذاکره)

این قواعد بر همه فازها حاکم‌اند. فازی تمام نمی‌شود اگر یکی از آن‌ها نقض شود.

  1. پارتیشن انحصاری اسناد. هر Sanad_Code حداکثر به یک ماژول انتقال تعلق دارد: افتتاحیه، فاکتور، دریافت/پرداخت، چک، هزینه/درآمد، یا سند دستی. عضویت در دو ماژول یعنی دوبل دفتری.
  2. رد کردن بهتر از حدس زدن. اگر خط سند به حساب، شخص، بانک یا صندوق قطعی نگاشت نشود، کل سند Failed می‌شود. انتخاب «اولین بانک» یا «اولین صندوق» ممنوع است.
  3. تراز در مبدأ. سندی با |جمع بدهکار − جمع بستانکار| > 0.01 منتقل نمی‌شود. بستن اختلاف به 30106 فقط برای افتتاحیه و فقط بعد از گزارش صریح مبلغ و علت مجاز است.
  4. ردیف کنترلی منتقل نمی‌شود. Col 005 و 006 (تراز افتتاحیه/اختتامیه هلو) و Sanad_Type = 5 که GL چک است، کپی نمی‌شوند. اثر آن‌ها از ماژول افتتاحیه و ماژول چک ساخته می‌شود.
  5. کد عمومی حسابیکس تغییر نمی‌کند. حساب‌های business_id IS NULL فقط خوانده می‌شوند. کمبود با حساب اختصاصی همان کسب‌وکار جبران می‌شود.
  6. اثر مالی با پیشوند کد حفظ می‌شود. طبقه‌بندی سود و زیان حسابیکس بر اساس پیشوند کد است (pnl_account_classification). حساب اختصاصی هزینه باید با 7 شروع شود، درآمد با 6، فروش با 5، بهای تمام‌شده با 4. کد الفبایی مثل HLO-601-0007 در بستن سال و صورت سود و زیان دیده نمی‌شود.
  7. زیردفتر جدا از حساب کل است. شخص، بانک، صندوق و تنخواه موجودیت‌اند و روی حساب‌های نوعی (10401/20201/10203/10202/10201) می‌نشینند. ساخت حساب عمومی جدید جایگزین تفصیل آن‌ها نیست.

معیار پذیرش نهایی (روی Holoo1 و هر دیتابیس مشتری)

برای هر سال مالی:

کنترل شرط قبول
پوشش اسناد تعداد SANAD غیرحذف‌شده = افتتاحیه + فاکتور (یکتا روی Sanad_Code) + Type20 + هزینه/درآمد + چک‌های دارای سند + دستی + عمداً ردشده با دلیل
عدم دوبل هیچ Sanad_Code در بیش از یک checkpoint موفق نیست
تراز جمع بدهکار و بستانکار اسناد منتقل‌شده در حسابیکس با جمع متناظر هلو، پس از کسر 005/006 و GL تکراری چک، در حد ۰٫۰۱ برابر است
ماهیت فروش هلو 901 فقط در گروه ۵، تخفیف فروش 903 در 50003، برگشت فروش 902 در 50002، خرید/برگشت/تخفیف خرید در گروه ۴
رد خاموش تعداد اسنادی که به‌خاطر fallback بانک/صندوق منتقل شده‌اند = ۰

۲. وضعیت فعلی (خط مبنا)

نگاشت فعلی در HolooSarfaslMapper.MapColToFixedCode فقط Col را به یک کد ثابت می‌برد. درخت SARFASL کپی نمی‌شود. تفصیل شخص از CustomerSarfasl و بانک از تطبیق شماره حساب در نام سرفصل حل می‌شود.

روی Holoo1 (۵۵۰ سرفصل فعال، ۳۲ کل):

واقعیت اثر
۵۳۸ فاکتور F/K به سند Type 13/14 با SaveFromFacture = 0 وصل‌اند اگر Invoices و ManualJournals هر دو روشن باشند، فروش/خرید دوبل می‌شود
نامزد «سند دستی» = ۵۴۲ رکورد: ۲۷۵ نوع ۱۳، ۲۶۵ نوع ۱۴، ۲ نوع ۴ تقریباً همه نوع ۱۳/۱۴ همان GL فاکتورند؛ سند دستی واقعی فقط نوع ۴ است (۲ سند)
903 به 60203 (سایر درآمدها) می‌رود تخفیف نقدی فروش از گروه فروش خارج می‌شود
802 902 803 904 905 207 403 501 506 001 002 بدون نگاشت‌اند هر سند دستی که این کل‌ها را داشته باشد کلاً رد می‌شود؛ در فاکتور هم اگر GL جدا خوانده شود گم می‌شوند
104 همیشه 10403 است در افتتاحیه، 104.0002 «اسناد در جریان وصول» باید 10404 باشد
معین‌های وام زیر 401 (وام تجارت، قوامین، رفاه) به 20201 + شخص می‌روند تسهیلات با حساب پرداختنی تجاری قاطی می‌شود
تطبیق هزینه با Contains روی نام؛ پیش‌فرض 70401 «هزینه تخفیفات - تعدیل حساب» (۲۱۶ سند) و مالیات/جریمه/صدقه به خرید خدمات می‌افتند
ResolveBank / ResolveCashOrPetty در نهایت FirstOrDefault با ۱۲ بانک و ۲ صندوق، مانده می‌تواند بی‌صدا به حساب غلط برود

این‌ها موضوع فاز ۱ تا ۳ هستند. فازهای بعدی روی همین موتور سوار می‌شوند.


۳. مدل هدف

۳.۱ کلید سرفصل

SarfaslKey = Col(3) + "|" + Moien + "|" + Tafzili

Moien و Tafzili خالی یعنی خود سطح کل/معین. نگاشت روی دقیق‌ترین کلید موجود انجام می‌شود: اول تفصیلی، بعد معین، بعد کل.

۳.۲ سه لایه تصمیم برای هر سرفصل

لایه چه وقت خروجی
A. زیردفتر 101 صندوق/تنخواه، 102 بانک، 103/401 شخص تجاری موجودیت حسابیکس + حساب نوعی ثابت
B. کد عمومی ماهیت با یک حساب seed یکی است account_id همان کد عمومی
C. حساب اختصاصی کسب‌وکار ماهیت در چارت عمومی نیست، یا معین هلو باید در گزارش جدا بماند POST /api/v1/accounts/business/{id}/create

ترتیب اجباری: A، سپس B، سپس C. ساخت حساب جدید وقتی کد عمومی درست وجود دارد ممنوع است (مثلاً 901 همیشه 50001 است، نه یک حساب فروش تازه).

۳.۳ قید ساخت حساب اختصاصی (از API موجود)

create_business_account این‌ها را تحمیل می‌کند:

  • parent_id اجباری است.
  • اگر والد عمومی است و برگ است (children خالی)، خطای INVALID_PUBLIC_PARENT می‌دهد. زیر 10401، 20201، 50001، 70401، 10203 نمی‌توان فرزند ساخت.
  • والد باید عمومی باشد یا متعلق به همان business_id.
  • یکتایی کد روی (business_id, code) است. کد عمومی با business_id NULL این یکتایی را نمی‌بندد؛ بنابراین کد اختصاصی نباید با کد عمومی یکی باشد، وگرنه ListAccountCodeMap بسته به ترتیب API ممکن است id غلط را بردارد.
  • account_type حساب اختصاصی مهاجرت = "0" (حساب عادی). نوع‌های person / bank / cash_register فقط روی حساب‌های سیستمی می‌مانند.

۳.۴ طرح کد اختصاصی

فرمت: {prefix گروه}9{Col سه رقم}{Moien چهار رقم} با pad صفر.

ماهیت والد (کد عمومی که از قبل فرزند دارد) نمونه کد پیشوند P&L / ترازنامه
هزینه عملیاتی بدون معادل 704 70496010007 برای هلو 601.0007 با 7 شروع می‌شود → هزینه عملیاتی
هزینه بانکی/غیرعملیاتی 709 70996010009 برای کارمزد اگر نخواهیم 70902 با 709 → غیرعملیاتی
درآمد بدون معادل 602 60297020001 با 602 → درآمد غیرعملیاتی
درآمد خدماتی بدون معادل 601 60197020003 با 601
وام/تسهیلات زیر ۴۰۱ 20501 205194010011 ترازنامه، بدهی غیرجاری
سایر بدهی جاری 203 20394010008 ترازنامه
پیش‌دریافت اختصاصی 204 20492070001 ترازنامه
دارایی ثابت اختصاصی 107 10792050001 ترازنامه
حقوق صاحبان سهام اختصاصی 301 30195010001 ترازنامه
انتظامی 801 80190010001 خارج از سود و زیان

9 بعد از پیشوند گروه، فضای کد را از کدهای پنج‌رقمی seed جدا می‌کند. نام حساب = Sarfasl_Name هلو، حداکثر طول مجاز API.

حساب اختصاصی یک‌بار در فاز ۲ ساخته می‌شود و در checkpoint با کلید ACC:{SarfaslKey} ذخیره می‌شود. اجرای مجدد، اگر کد موجود باشد، همان id را لینک می‌کند (ACCOUNT_CODE_NOT_UNIQUE → جستجو با code).

۳.۵ جدول نگاشت لایه B (جایگزین MapColToFixedCode)

نگاشت پیش‌فرض سیستمی، قابل override در پروفایل کسب‌وکار:

کلید هلو کد حسابیکس یادداشت
101.0001 و هر صندوق 10202 + cash_register_id معین 0002 یا نام حاوی «تنخواه» → 10201 + petty_cash_id
102.* 10203 + bank_account_id تطبیق فقط با شماره حساب یا نقشه صریح؛ بدون fallback
103.* شخص 10401 اگر بدهکار خالص، 20201 اگر بستانکار خالص جهت خط سند تعیین‌کننده است، نه فقط Col
104.0001 10403 اسناد دریافتنی
104.0002 10404 اسناد در جریان وصول تفکیک اجباری
104 با نام ضمانت/سپرده 10302 / 10303
106 10102 فقط مبلغ ریالی افتتاحیه؛ مقدار کالا جدا و با cost_price = 0
107.0004 و نام مالیات/عوارض خرید 10104
107 سایر 10101 پیش‌پرداخت
205 10704 اثاثیه اگر نام زمین/ساختمان/وسیله باشد → 10701/10702/10703
401 شخص تجاری 20201 + person_id
401 با طبقه «وام» حساب اختصاصی زیر 20501 شخص اختیاری در شرح، نه تفصیل AP
402 20202 وصول/صدور واقعی از ماژول چک؛ در افتتاحیه سطر تجمیعی مجاز است
207 / 403 20401 یا 20402
404 30105 جاری شرکا اگر تفصیل شریک به شخص وصل است، person_id هم پر شود
501 / 506 30101
502 30106 سود و زیان سنوات؛ با حساب بستن اختلاف قاطی نشود
503 40001 بهای تمام‌شده
601.{moien} جدول صریح بخش ۳.۶
702.{moien} جدول صریح بخش ۳.۶
801 در فاکتور خرید تولید می‌شود؛ در سند دستی اگر مستقل بود 40001 سمت بدهکار خرید فقط وقتی فاکتور وصل نیست
802 40002
803 40003
901 50001
902 50002
903 50003 اصلاح باگ فعلی 60203
904 50003 با علامت معکوس در شرح، یا حساب اختصاصی زیر گروه ۵ اگر باید جدا بماند تخفیف نقدی برگشت از فروش
905 40003 تخفیف نقدی برگشت از خرید
001 80101
002 80102
005 006 هیچ حذف از خطوط
105 موجودی پایان دوره هیچ، مگر سند اختتامیه که فاز ۷ جدا تصمیم می‌گیرد حساب کنترلی انبار هلو
620 کنترل هزینه هیچ تا وقتی سندی با مبلغ واقعی دیده شود؛ اگر دیده شد حساب اختصاصی زیر 704 با هشدار

هر کلیدی که در این جدول نیست و در SND_LIST مبلغ غیرصفر دارد، قبل از انتقال باید یا به لایه B اضافه شود یا در لایه C ساخته شود. انتقال با «رد شدن خاموش خط» ممنوع است.

۳.۶ نگاشت صریح هزینه و درآمد (جایگزین keyword)

حداقل برای معین‌های موجود Holoo1. پروفایل هر مشتری همین جدول را گسترش می‌دهد.

هلو 601 کد
0001 آب 70503
0002 برق 70504
0003 تلفن 70506
0004 0064 کرایه، 0066 اجاره 70405
0005 مطالبات مشکوک / سوخت چک 70802
0006 ضایعات 70407
0008 کمیسیون 70702
0009 کارمزد بانک 70902
0052 حمل 70403
0060 حقوق 70201
0063 خوراک 70502
0065 مصرفی 70406
0067 سوخت 70501
0068 بیمه 70211
0070 جریمه دیرکرد 70903
0007 تخفیف تعدیل، 0055 گرد کردن، 0056–0062 عوارض و مالیات، 0058 کد اقتصادی، 0069 صدقه حساب اختصاصی زیر 704 یا 709؛ پیش‌فرض 70401 حذف می‌شود
هلو 702 کد
0003 حق‌العمل 60101
0004 تخلیه/حمل 60104
0001 0002 سایر 60203 مگر کاربر جدا بخواهد

قانون: اگر نام در جدول نبود، سند هزینه Failed با پیام «معین بدون نگاشت» است. ساخت خودکار حساب اختصاصی فقط وقتی مجاز است که کاربر در پیش‌نمایش فاز ۳ گزینه «ایجاد حساب» را زده باشد.


۴. پارتیشن اسناد (فاز ۱)

الگوریتم طبقه‌بندی، قبل از هر API call، روی کل SANAD غیرحذف‌شده یک برچسب می‌زند. برچسب‌ها هم‌پوشانی ندارند. ترتیب ارزیابی:

1. Sanad_Code = سند افتتاحیه (فعلی: Sanad_Code = 1، باید با Comment/تاریخ اول سال هم تأیید شود)
      → OPENING
2. Col فقط 005/006 یا سند بدون مبلغ واقعی
      → SKIP_CONTROL
3. Sanad_Type = 5 OR Sanad_Code / Sanad_Code2 در جدول Check
      → CHECK_GL_SKIP   (اثر از ماژول چک)
4. EXISTS فاکتور غیرحذف با همین Sanad_Code
      OR SaveFromFacture = 1 و Type in (0,13,14)
      → INVOICE_GL_SKIP  (اثر از فاکتور + حواله انبار)
5. وجود خط 601 یا 702 با مبلغ، و طرف‌حساب فقط در {101,102,103,401}
      و |آیتم − طرف| <= 0.01
      → EXPENSE_INCOME
6. Sanad_Type = 20 و شرط ۵ برقرار نیست
      و طرف شخص + طرف 101 یا 102
      → RECEIPT_PAYMENT
7. بقیه اسناد با حداقل دو خط مبلغ‌دار و تراز <= 0.01
      → MANUAL
8. هر چه ماند
      → UNCLASSIFIED  (باید صفر شود یا با دلیل در گزارش بماند)

روی Holoo1 انتظار بعد از این قانون:

  • Type 13/14 متصل به فاکتور از MANUAL خارج می‌شوند (۵۳۸ سند).
  • MANUAL واقعی ≈ نوع ۴ (۲ سند) به‌علاوه هر سند متوازنی که به فاکتور، چک، Type20 و 601/702 نخورد.
  • Type 0 با SaveFromFacture = 1 (۲۷۲۵ سند) فقط از مسیر فاکتور می‌رود.

خروجی فاز ۱ یک جدول ممیزی است، نه سند حسابیکس:

Sanad_Code, Date, Type, SaveFromFacture, Bucket, Debit, Credit, ColSet, Blocker

Blocker خالی یعنی قابل انتقال. مقدارش یکی از این‌هاست: unmapped_sarfasl, unresolved_person, unresolved_bank, unbalanced, missing_dimension.


۵. فازهای اجرایی

هر فاز یک تحویل قابل تست دارد. فاز بعدی شروع نمی‌شود مگر معیار خروج فاز قبل روی Holoo1 سبز باشد. کدنویسی هر فاز جدا و قابل review است.

فاز ۰ — قفل محدوده و ابزار سنجش

هدف: قبل از تغییر نگاشت، بتوان اختلاف را اندازه گرفت.

کارها:

  1. اسکریپت خواندنی (فقط SELECT) که برای یک دیتابیس هلو این‌ها را بنویسد:
    • توزیع Col_Code در SND_LIST با مبلغ.
    • توزیع Bucket طبق بخش ۴.
    • فهرست SarfaslKeyهای بدون نگاشت لایه B.
    • فهرست اسنادی که هم فاکتور دارند هم در فیلتر فعلی ManualJournals می‌افتند.
  2. ثابت کردن تلرانس پول: ۰٫۰۱ ریال، همان ApiDateFormat.RoundMoney.
  3. تعریف شناسه ردیابی در extra_info همه اسناد حسابیکس: holoo_sanad_code, holoo_bucket, holoo_db.

خروج: گزارش baseline برای Holoo1 ذخیره شود و اعداد بخش ۲ همین سند را تأیید کند. هیچ write به حسابیکس در این فاز نیست.


فاز ۱ — کلاسه‌بند اسناد و بستن دوبل

هدف: Manual Journals دیگر GL فاکتور را برنمی‌دارد.

کارها در HolooDocumentReader.ReadManualJournalsInRange و شمارنده ماژول:

  1. شرط جدید: NOT EXISTS (SELECT 1 FROM FACTURE f WHERE f.Sanad_Code = s.Sanad_Code AND ISNULL(f.[Delete],0)=0).
  2. Sanad_Type IN (13,14) حتی بدون ردیف فاکتور، اگر SaveFromFacture=1 باشد، از دستی خارج بماند (الان با فیلتر SaveFromFacture=0 تا حدی هست؛ شرط فاکتور هنوز لازم است چون ۵۳۸ سند SaveFromFacture=0 ولی فاکتور دارند).
  3. Type 5 و پیوند Check.Sanad_Code / Sanad_Code2 سر جایش بماند.
  4. اسناد UNCLASSIFIED در preflight به‌صورت error بیایند، نه warning.

خروج روی Holoo1:

  • تعداد سند دستی کاندید از ۵۴۲ به حدود ۲ (نوع ۴) به‌علاوه موارد واقعاً بدون فاکتور برسد.
  • اشتراک Sanad_Code بین فاکتورهای F/K/Y/X/Z و لیست دستی = ۰.
  • دو سند نوع ۴ (16891 بانک/شخص و 23923 صندوق/شخص) هنوز در لیست دستی باشند.

ریسک: فاکتور حذف‌شده با سند زنده. شرط حذف فاکتور باید باشد تا سند یتیم به دستی برگردد و گم نشود.


فاز ۲ — کاتالوگ نگاشت و ساخت حساب اختصاصی

هدف: هر SarfaslKey دارای مبلغ، قبل از انتقال سند، یک مقصد قطعی داشته باشد.

طراحی کامپوننت SarfaslCatalog (جایگزین تدریجی توابع Shared فعلی):

Resolve(line) →
  Decision {
    Kind: Person | Bank | Cash | Petty | FixedAccount | BusinessAccount | Skip | Block
    AccountCode or AccountId
    DimensionId?     'person / bank / cash / petty
    BlockReason?
  }

کارها:

  1. داده نگاشت لایه B را از کد جدا کنید (فایل یا جدول داخل checkpoint). MapExpenseToFixedCode مبتنی بر Contains حذف شود؛ جدول بخش ۳.۶ منبع حقیقت است.
  2. API کلاینت: CreateBusinessAccount(businessId, parentCode, code, name).
    • parent را از ListAccountCodeMap با کد والد پیدا کنید.
    • اگر INVALID_PUBLIC_PARENT برگشت، والد را یک سطح بالاتر ببرید فقط اگر آن سطح در جدول ۳.۴ مجاز باشد؛ در غیر این صورت Block.
  3. ترتیب ساخت: اول والدهای اختصاصی (اگر لازم شد)، بعد برگ‌ها. در عمل فاز اول فقط برگ زیر والد عمومی غیربرگ می‌سازد؛ درخت چندسطحی اختصاصی لازم نیست.
  4. حساب‌های سیستمی که نوع‌دارند (account_type شخص/بانک/صندوق/چک/کالا) را هرگز به‌عنوان مقصد سند دستیِ بدون dimension انتخاب نکنید. API سند در این حالت یا رد می‌کند یا مانده تفصیل را خراب می‌کند.
  5. ResolveBank: حذف Values.FirstOrDefault() و حذف تطبیق Contains دوطرفه شماره حساب. تطبیق مجاز:
    • نقشه صریح ACOUND_N.Id → bank_account_id که در انتقال پایه ساخته شده.
    • برابری دقیق Account_N با شماره داخل نام سرفصل.
    • اگر هیچ‌کدام نبود: Block / unresolved_bank.
  6. همین قاعده برای صندوق و تنخواه: بیش از یک صندوق ⇒ نقشه Cash.Id به سرفصل، نه اولین رکورد.
  7. طبقه 401: اگر نام معین با الگوهای وام|تسهیلات|قسط جور است، Kind = BusinessAccount زیر 20501، نه Person+AP. لیست استثنا در پیش‌نمایش قابل اصلاح است (کارمند می‌تواند AP بماند).

خروج:

  • برای Holoo1، هر Col دارای مبلغ در افتتاحیه (101,102,103,104,106,107,205,401,402,404,502) تصمیم غیر Block دارد.
  • 104.0002 به کد 10404 حل می‌شود.
  • 903 به 50003 حل می‌شود.
  • معین 601.0007 یا حساب اختصاصی دارد یا Block است؛ هرگز 70401 پیش‌فرض نیست.
  • اجرای دوباره کاتالوگ، حساب تکراری نمی‌سازد.

وابستگی حسابیکس: اگر ساخت زیر یک والد عمومی به‌خاطر برگ بودن شکست خورد، آن مورد در همین فاز با انتخاب والد مجاز ۳.۴ حل می‌شود. تغییر API حسابیکس لازم نیست مگر بخواهیم زیر برگ عمومی هم فرزند بسازیم؛ آن را عمداً نمی‌خواهیم چون برگ‌های عمومی نوع‌دارند و رفتار سند را عوض می‌کنند.


فاز ۳ — پیش‌نمایش انسانی و قفل پروفایل

هدف: اپراتور قبل از ارسال سند، نگاشت را ببیند و تأیید کند. انتقال اسناد تا قفل پروفایل شروع نشود.

کارها در UI ویزارد (بعد از اتصال SQL و انتخاب کسب‌وکار):

  1. گرید سرفصل: نام هلو، مبلغ گردش بدهکار/بستانکار، تصمیم پیشنهادی، مقصد، وضعیت (آماده / نیاز به ساخت حساب / مسدود).
  2. سه عمل روی ردیف مسدود یا قابل تغییر:
    • نگاشت به کد عمومی موجود (لیست حساب‌های همان کسب‌وکار + عمومی).
    • ایجاد حساب اختصاصی (نام قابل ویرایش، والد از لیست مجاز ۳.۴، کد خودکار).
    • «عمداً منتقل نشود» با دلیل اجباری. این ردیف در گزارش پذیرش می‌آید و سندهای درگیر را Block می‌کند مگر کل سند فقط از همین ردیف‌های معاف تشکیل نشده باشد؛ اگر یک خط سند معاف است، کل سند Block است تا تراز نشکند.
  3. ذخیره پروفایل کنار checkpoint: sarfasl-profile.json شامل overrideها و id حساب‌های ساخته‌شده.
  4. پیش‌نمایش Bucketها: تعداد و جمع مبلغ هر ماژول، به‌علاوه تعداد Blocker.

خروج: روی Holoo1 اپراتور می‌تواند بدون ارسال سند، ببیند وام‌های 401 به 20501 می‌روند و ۵۳۸ سند فاکتوری در دستی نیستند. پروفایل قفل‌شده ورودی فاز ۴ است.


فاز ۴ — افتتاحیه سال اول

هدف: تراز افتتاحیه هلو، بدون دوبل موجودی کالا، در سند افتتاحیه حسابیکس بنشیند.

ورودی: خطوط ReadOpeningLines منهای 005/006، به‌علاوه مقدار First_exist کالا فقط برای کاردکس.

قواعد:

  1. هر خط از SarfaslCatalog.Resolve رد شود. یک خط Block ⇒ افتتاحیه ثبت نشود (الان خط skip می‌شود و اختلاف به 30106 می‌رود؛ این رفتار حذف می‌شود).
  2. تجمیع مجاز است فقط برای یک مقصد یکسان (همان شخص، همان بانک، همان کد حساب). تجمیع 401 وام با 401 تأمین‌کننده ممنوع است چون Kind فرق دارد.
  3. 104.0001 و 104.0002 دو سطر جدا (10403 و 10404).
  4. موجودی کالا: سطر ریالی از Col 106 روی 10102 می‌ماند. سطر مقدار با cost_price = 0 فقط کاردکس را پر می‌کند تا GL دوبل نشود. اگر جمع ریالی First_exist * cost با Col 106 بیش از تلرانس اختلاف داشت، در گزارش بیاید؛ سند را با میانگین‌گیری خاموش درست نکنید.
  5. اختلاف باقی‌مانده بعد از نگاشت کامل: یک سطر به 30106 با شرح «اختلاف تراز افتتاحیه هلو» فقط اگر گزارش فاز ۰ همان اختلاف را در خود سند هلو (پس از حذف 005/006) نشان بدهد. اگر اختلاف از خط Blockشده آمده، ثبت نکنید.
  6. شخص افتتاحیه: 103 بدهکار خالص → 10401؛ 401 تجاری بستانکار خالص → 20201. وام‌ها حساب اختصاصی، بدون person_id اجباری.

خروج روی Holoo1: سند افتتاحیه Sanad_Code = 1 یا کامل ثبت می‌شود یا با فهرست خطوط Block متوقف می‌شود. جمع بدهکار و بستانکار ارسالی برابر است. حساب 30106 فقط به اندازه مانده خود Col 502 به‌علاوه اختلاف واقعی هلو بستانکار/بدهکار می‌شود، نه به اندازه خطوط جاافتاده.


فاز ۵ — اسناد عملیاتی (فاکتور، دریافت، چک، هزینه)

هدف: اسنادی که حسابیکس برایشان سند تخصصی دارد، از همان API بروند تا GL و زیردفتر با هم ساخته شود.

فاکتور

  • منبع حقیقتcommercial همان FACTURE/FACTART است، نه سند Type 13/14.
  • انواع: F فروش، K خرید، Y برگشت فروش، X برگشت خرید، Z مصرف مستقیم.
  • تسویه نقد/بانک از hint سند، با Catalog.resolve؛ اگر resolve نشد پرداخت روی فاکتور ننشیند و مانده نسیه بماند، و سند در گزارش «تسویه نامشخص» بیاید. چسباندن به صندوق پیش‌فرض ممنوع.
  • FCheck همچنان نسیه می‌ماند تا ماژول چک اسناد دریافتنی/پرداختنی را جابه‌جا کند. شرط پذیرش: جمع چک‌های متصل به فاکتور با FCheck همان فاکتور در حد تلرانس یکی باشد؛ اختلاف گزارش شود.
  • حواله انبار فقط از ماژول WarehouseDocs و فقط برای فاکتورهایی که حواله‌شان در هلو اثر مقداری دارد. صدور دوباره GL موجودی از سند حسابداری هلو ممنوع.

دریافت/پرداخت Type 20

  • فقط Bucket RECEIPT_PAYMENT.
  • شخص و بانک/صندوق هر دو باید Resolve شوند وگرنه Fail همان سند.
  • اگر سند Type 20 خط 601/702 دارد، در این ماژول نیست (مال هزینه/درآمد است). این شرط الان هست؛ تستش را نگه دارید.

چک

  • ایجاد، عودت، وصول فقط از ماژول چک.
  • هیچ سندی از Type 5 یا Check.Sanad_Code* دوباره به‌صورت دستی پست نشود.
  • بانک وصول باید Resolve دقیق شود. نبود بانک = Fail وصول، نه اولین بانک.
  • حالت‌هایی که باید در تست باشند: دریافت، پرداخت، در جریان وصول (104.0002)، برگشت، ابطال. اگر API حسابیکس برای «خواباندن به حساب در جریان وصول» عمل جدا ندارد، سند دستی فقط برای همان شکاف با حساب 10404 مجاز است و باید در پارتیشن با برچسب CHECK_SUPPLEMENT باشد تا با سند صدور چک دوبل نشود. این شکاف در شروع فاز ۵ با یک سند نمونه Holoo1 (مثلاً حوالی Sanad 43051) اندازه‌گیری می‌شود؛ اگر API چک خودش 10403 → 10404 را می‌زند، مکمل دستی ساخته نمی‌شود.

هزینه/درآمد

  • آیتم‌ها فقط از جدول ۳.۶ یا حساب اختصاصی تأییدشده.
  • طرف‌حساب خارج از شخص/صندوق/بانک ⇒ سند به MANUAL می‌رود (الان Return Nothing یعنی Fail؛ فاز ۵ آن را إعادة طبقه‌بندی می‌کند تا سند ترکیبی گم نشود).
  • اختلاف مبلغ آیتم و طرف بیش از ۰٫۰۲ ⇒ Fail، بدون سرشکن.

خروج: برای یک سال نمونه Holoo1 (ترجیحاً آخرین سال)، شمارش فاکتور منتقل‌شده = شمارش فاکتور غیرحذف همان بازه. شمارش Type20 و هزینه همین‌طور. هیچ‌کدام از این Sanad_Codeها در checkpoint دستی نیستند.


فاز ۶ — سند دستی کامل

هدف: Bucket MANUAL خط‌به‌خط با Catalog به POST .../documents/manual برود.

قواعد BuildManualJournalPayload:

  1. خط Skip (005/006) حذف می‌شود و در جمع تراز نمی‌آید.
  2. خط Block ⇒ کل سند Fail با ذکر Col|Moien|Name.
  3. خط شخص: account_id از جهت (AR/AP) + person_id.
  4. خط بانک/صندوق/تنخواه: account_id نوعی + dimension. بدون dimension ارسال نشود.
  5. خط حساب عادی: account_id عمومی یا اختصاصی.
  6. |bed − bes| > 0.01 ⇒ Fail.
  7. کمتر از دو خط ⇒ Fail.
  8. extra_info.holoo_sanad_code اجباری برای برگشت‌پذیری.

خروج روی Holoo1: دو سند نوع ۴ یا منتقل می‌شوند یا دلیل Block مشخص دارند. جمع اسناد MANUAL موفق + ناموفق + SKIP = تعداد Bucket MANUAL. ناموفق صفر است مگر پروفایل فاز ۳ چیزی را عمداً معاف کرده باشد.


فاز ۷ — اثبات تراز و گزارش پذیرش

هدف: محصول بدون گزارش سبز، «تمام‌شده» اعلام نشود.

کارها:

  1. گزارش سمت هلو (SQL) و سمت حسابیکس (API تراز آزمایشی یا جمع اسناد) برای هر سال:
    • جمع بدهکار/بستانکار به تفکیک Bucket.
    • جمع به تفکیک کد حسابیکس مقصد.
  2. مقایسه:
    • گروه فروش هلو (901−902−903±904) با گردش 50001/50002/50003.
    • گروه خرید (801−802−803±905) با 40001/40002/40003 فقط برای اسنادی که از مسیر دستی/افتتاحیه آمده‌اند؛ فاکتور خرید را حسابیکس در بهای تمام‌شده/موجودی طبق سیستم دائمی خودش می‌نشاند. این تفاوت سیستم دائمی در گزارش با یک سطر توضیحی می‌آید و به‌عنوان خطا شمرده نمی‌شود، به شرطی که جمع فاکتور خرید هلو با جمع فاکتور خرید حسابیکس برابر باشد.
    • اشخاص: مانده هر C_Code در هلو در پایان سال با مانده تفصیل همان شخص.
    • بانک: مانده هر ACOUND_N با مانده همان بانک.
  3. فهرست اسناد Fail با دلیل، قابل خروجی CSV.
  4. آستانه قبول: اختلاف توضیح‌داده‌نشده = ۰. اختلاف سیستم دائمی موجودی فقط در سطر توضیحی گزارش مجاز است.

خروج: یک فایل گزارش برای Holoo1 که بخش «اختلاف بدون توضیح» خالی است، یا فهرست دقیق کار باقی‌مانده را دارد. فاز تمام است فقط در حالت اول.


فاز ۸ — سخت‌سازی محصول

هدف: رفتار بالا برای دیتابیس غیر از Holoo1 هم تکرار شود.

کارها:

  1. Preflight قبل از انتقال: اگر Bucket UNCLASSIFIED یا سرفصل Block بدون معافیت وجود دارد، دکمه شروع غیرفعال است.
  2. Resume: checkpoint فعلی حفظ شود؛ حساب اختصاصی و پروفایل نگاشت بخشی از checkpoint باشند تا اجرای دوباره حساب نسازد و سند دوبل نزند.
  3. تست خودکار روی کپی کوچک‌شده از الگوهای Holoo1:
    • فاکتور Type13 با SaveFromFacture=0 دوبل نشود.
    • 903 به 50003 برود.
    • 104.0002 به 10404 برود.
    • وام 401 به AP نرود.
    • بانک نامطابق سند را Fail کند.
    • هزینه ناشناس بدون تأیید کاربر به 70401 نرود.
    • ساخت حساب دوم با همان کد، id قبلی را برگرداند.
  4. لاگ مهاجرت برای هر سند: کلید هلو، id حسابیکس، bucket، جمع مبلغ.

خروج: مجموعه تست بالا سبز است و preflight یک دیتابیس مصنوعی با سرفصل ناشناس را متوقف می‌کند.


۶. ترتیب اجرا و وابستگی

فاز ۰ سنجش
  → فاز ۱ پارتیشن (دوبل را می‌بندد حتی قبل از نگاشت کامل)
    → فاز ۲ کاتالوگ + ساخت حساب
      → فاز ۳ قفل پروفایل
        → فاز ۴ افتتاحیه
          → فاز ۵ عملیاتی
            → فاز ۶ دستی
              → فاز ۷ اثبات
                → فاز ۸ تست و قفل محصول

فاز ۱ را می‌توان مستقل از فاز ۲ منتشر کرد چون فقط جلوی دوبل را می‌گیرد و به حساب جدید نیاز ندارد. فاز ۴ به قفل فاز ۳ وابسته است. فاز ۶ بدون فاز ۲ سندهای دارای کلِ بدون نگاشت را همچنان Fail می‌کند؛ این Fail درست است و نباید با fallback پوشانده شود.


۷. آنچه عمداً خارج از انتقال دفتری است

مورد رفتار
حساب‌های عمومی حسابیکس ویرایش و حذف نمی‌شوند
درخت کامل SARFASL به‌عنوان کپی یک‌به‌یک کد هلو ساخته نمی‌شود؛ فقط معین‌هایی که معادل عمومی ندارند و مبلغ دارند، با کد اختصاصی بخش ۳.۴ ساخته می‌شوند
سند Type 5 و GL چک کپی نمی‌شود
005 / 006 کپی نمی‌شود
موجودی مقداری کالا در افتتاحیه کاردکس جدا؛ GL فقط از Col 106
سیستم دائمی حسابیکس در مقابل ثبت خرید/فروش هلو فاکتور از API فاکتور می‌رود تا موجودی و بهای تمام‌شده را خود حسابیکس بسازد؛ سند Type 13/14 همان فاکتور دوباره پست نمی‌شود

۸. تعریف تمام‌شدن کار

انتقال وقتی بی‌نقص است که هر چهار شرط با هم برقرار باشند:

  1. پارتیشن بخش ۴ هیچ Sanad_Code را به دو ماژول موفق نداده باشد.
  2. هر سرفصل دارای مبلغ، تصمیم قفل‌شده در پروفایل داشته باشد (نگاشت عمومی، حساب اختصاصی، یا معافیت با دلیل).
  3. گزارش فاز ۷ اختلاف توضیح‌داده‌نشده نداشته باشد.
  4. تست‌های فاز ۸ روی الگوی Holoo1 سبز باشند.

تا قبل از این چهار شرط، محصول نباید به‌عنوان انتقال کامل حسابداری عرضه شود.