# پرداخت کیف‌پولی بله برای پلانک

این اتصال بر اساس [مستندات رسمی بله](https://docs.bale.ai/) ساخته شده است. پرداخت از طریق کیف پول بله و ربات اختصاصی پذیرنده انجام می‌شود. `createInvoiceLink` مخصوص مینی‌اپ است و برای انتقال مستقیم از وب‌سایت استفاده نمی‌شود.

## نصب

1. پس از مهاجرت‌های موجود، به‌ترتیب `supabase/migrations/202610190001_bale_payments.sql`، `supabase/migrations/202610190002_wallet_funding.sql` و `supabase/migrations/202610190003_wallet_funding_read_context.sql` را روی همان پروژهٔ Supabase نصب کنید. این مجموعه اتصال بله، صف بررسی مالی و اصلاح خواندن وضعیت حساب را فراهم می‌کند و داده‌های قبلی را حذف نمی‌کند. قبل از اجرای دوباره، وضعیت مهاجرت‌ها و وابستگی‌ها را بررسی کنید؛ همهٔ مهاجرت‌های قدیمی را کورکورانه دوباره اجرا نکنید.
2. تابع `supabase/functions/bale-payments/index.ts` و فایل مشترک `supabase/functions/_shared/bale-payments.ts` را با نام `bale-payments` منتشر کنید. تنظیم `verify_jwt = false` از `supabase/config.toml` لازم است چون بله JWT کاربران Supabase ندارد. خود تابع، درخواست‌های کاربر و مدیر را با Supabase Auth و وب‌هوک را با مسیر محرمانه تصادفی اعتبارسنجی می‌کند.
3. متغیر سمت تابع `BALE_ALLOWED_ORIGINS` را به مبدأهای دقیق مارکت‌پلیس و مدیریت، با کاما بین آن‌ها، تنظیم کنید. پیش‌فرض برای توسعه شامل `http://localhost:3000` و `http://localhost:3001` و معادل‌های `127.0.0.1` است. برای سایت منتشرشده، مبدأ HTTPS هر دو سایت را وارد کنید.
4. در مدیریت، اتصالات، «پرداخت با بله»، نام کاربری ربات اختصاصی پلانک و توکن ربات را وارد کنید. توکن پرداخت کیف‌پولی نیز از [BotFather بله](https://ble.ir/botfather) دریافت می‌شود. کلیدها در Supabase Vault نگهداری می‌شوند و در خروجی مدیریت برگردانده نمی‌شوند.
5. ابتدا حالت آزمایشی را ذخیره کنید. دکمهٔ «اتصال و ثبت وب‌هوک» هویت ربات و وب‌هوک را بررسی می‌کند. این عملیات وب‌هوک فعلی ربات را جایگزین می‌کند؛ ربات باید مخصوص همین اتصال باشد.
6. گزینهٔ پذیرش پرداخت را روشن کنید. نمایش فعال در مارکت‌پلیس به ذخیرهٔ تنظیمات کامل و موفقیت بررسی اتصال وابسته است. سبز شدن وضعیت ربات به‌تنهایی اثبات پرداخت واقعی نیست.
7. پس از تست توسط مالک حساب، توکن پرداخت واقعی را ذخیره و حالت واقعی را انتخاب کنید؛ بررسی اتصال را دوباره انجام دهید. تا تعیین تکلیف پرداخت‌های باز، تغییر اطلاعات اتصال یا حالت پرداخت مسدود است.

بدون انتشار تابع، نصب مهاجرت و اطلاعات پذیرنده، پرداخت واقعی فعال نیست. توکن سرویس Supabase هرگز در مارکت‌پلیس یا مدیریت قرار نمی‌گیرد؛ فقط محیط امن تابع آن را در اختیار دارد.

## مسیر پرداخت

- کاربر احراز‌شده مبلغ تومان را در پلانک وارد می‌کند. سرور هویت کاربر را از نشست می‌گیرد، مبلغ را دقیقاً به ریال تبدیل و درخواست یکتا ایجاد می‌کند.
- لینک تصادفی و کوتاه‌عمر ربات برگردانده می‌شود. با باز کردن آن در بله، فاکتور همان درخواست در گفت‌وگوی خصوصی ایجاد می‌شود. اطلاعات هویتی پلانک به بله فرستاده نمی‌شود؛ فقط مبلغ، شرح شارژ و شناسهٔ تصادفی فاکتور ارسال می‌شود.
- درخواست پیش‌پرداخت به کاربر بله، مبلغ، ریال و شناسهٔ تراکنش مقید می‌شود. این مرحله موجودی را تغییر نمی‌دهد.
- پس از رسید، سرور از `inquireTransaction` استعلام می‌گیرد. مبلغ، شناسه، پرداخت‌کننده و وضعیت `paid` باید مطابق درخواست ثبت‌شده باشند.
- نتیجهٔ معتبر بله ابتدا به‌عنوان مدرک پرداخت ثبت می‌شود و وضعیت مشتری `pending_review` می‌ماند. تأیید پرداخت از بله به‌تنهایی موجودی را افزایش نمی‌دهد.
- در حالت پیش‌فرض، مالک سامانه باید درخواست را در صف بررسی مالی تأیید کند. ثبت نهایی تراکنش، گزارش مالی و افزایش موجودی به‌صورت اتمی انجام می‌شود؛ رسید تکراری یا تأیید هم‌زمان باعث شارژ دوباره نمی‌شود.
- صفحهٔ واریز وضعیت را در زمان باز بودن صفحه بررسی می‌کند. مدیر نیز می‌تواند با «بازبینی پرداخت‌های معلق» حداکثر پنج درخواست را در هر نوبت دوباره از بله استعلام کند. این دکمه تأیید دستی واریز نیست.

هر درخواست جدید ابتدا در انتظار بررسی ثبت می‌شود. دو گزینهٔ هر درخواست، `automatic_enabled` و `manual_required`، به‌طور پیش‌فرض روشن هستند؛ بنابراین تأیید دستی الزامی است. ثبت خودکار فقط با مدرک معتبر، روشن بودن گزینهٔ اول و خاموش بودن الزام دستی مجاز است. درخواست ردشده یا مشکل‌دار با دریافت دوبارهٔ رسید خودکار شارژ نمی‌شود. مدیر نمی‌تواند نبود مدرک پرداخت واقعی را با تأیید دستی دور بزند.

## حالت آزمایشی و بازیابی

در حالت آزمایشی همیشه توکن رسمی `WALLET-TEST-1111111111111111` به بله فرستاده می‌شود، حتی اگر توکن واقعی قبلاً ذخیره شده باشد. پرداخت تأییدشدهٔ آزمایشی نیز ابتدا `pending_review` است. پس از تأیید درخواست، فقط موجودی آزمایشی جداگانه افزایش می‌یابد و نتیجه `test_paid` می‌شود؛ موجودی واقعی و قابل برداشت تغییر نمی‌کند. سقف هر درخواست تازهٔ بله در حالت آزمایشی ۱۰۰ میلیون تومان است و مبلغ بالاتر با `test_deposit_limit` رد می‌شود.

هر فاکتور فقط یک بار ارسال می‌شود. در قطع ارتباط هنگام ارسال، ارسال مجدد خودکار نداریم چون ممکن است بله فاکتور اول را دریافت کرده باشد. کاربر ابتدا همان گفت‌وگو را بررسی می‌کند؛ اگر فاکتوری نرسیده باشد، پس از پایان اعتبار ۱۵ دقیقه‌ای، درخواست تازه می‌سازد. فاکتور قبلی بعد از انقضا نمی‌تواند پیش‌پرداخت جدید بگیرد.

تراکنشی که پیش‌پرداخت آن قبلاً پذیرفته شده، حتی پس از انقضای لینک، خاموش شدن پذیرش پرداخت یا تعلیق کاربر، با تأیید معتبر بله قابل ثبت به‌عنوان مدرک پرداخت است؛ الزام بررسی مالی همچنان برقرار می‌ماند. در خطای موقت پایگاه داده، رسید دوباره یا استعلام مجدد همان تراکنش بدون شارژ تکراری امکان ثبت را فراهم می‌کند. پس از ثبت مدرک، پیگیری وضعیت بررسی از پایگاه داده انجام می‌شود و استعلام تکراری بله لازم نیست.

اطلاعات اتصال و وضعیت درخواست‌ها دائمی هستند. مسیر محرمانهٔ وب‌هوک، شناسهٔ داخلی فاکتور، توکن‌های پرداخت و شناسهٔ گفت‌وگوی بله وارد گزارش عمومی یا اعلان‌ها نمی‌شوند. گزارش مدیریتی فقط اطلاعات لازم برای پیگیری واریز را نمایش می‌دهد.

## بررسی پیش از پذیرش واقعی

- تست کیف پولی با ربات پذیرنده: ابتدا `pending_review` و بدون افزایش موجودی؛ پس از تأیید مدیر، `test_paid` و افزایش فقط موجودی آزمایشی غیرقابل برداشت.
- کنترل راه‌اندازی وب‌هوک و دریافت رسید از خود بله، در محیط HTTPS منتشرشده.
- کنترل موفقیت/لغو، دریافت دوبارهٔ رسید، استعلام دستی و نمایش نتیجه در حساب کاربر و فعالیت‌های مدیریت.
- اولین پرداخت واقعی را خود مالک حساب انجام دهد؛ پذیرش تراکنش واقعی نیاز به توکن معتبر پذیرنده دارد.

تست‌های خودکار `tests/bale-payments.test.mjs` و `tests/bale-payments-db.test.mjs` پاسخ‌های سرویس و پایگاه دادهٔ آزمایشی را به کار می‌برند؛ موفقیت آن‌ها جایگزین آزمون واقعی بله نیست.

## واریز USDT و تنظیم اتصال

شبکه‌های پشتیبانی‌شده فقط اتریوم اصلی (`ethereum`، ERC-20) و ترون (`tron`، TRC-20) هستند. برای هر شبکه، نشانی کیف پول شرکت و کلید ارائه‌دهندهٔ استعلام را در تنظیمات واریز تتر ثبت و سپس پذیرش همان شبکه را فعال کنید. مقصد، کیف پول شرکت است؛ نشانی قرارداد خود USDT مقصد واریز نیست. نشانی اتریوم از نظر قالب و نشانی ترون از نظر Base58Check بررسی می‌شود. شبکه‌های دیگر از جمله BSC پشتیبانی نمی‌شوند.

- اتریوم از Alchemy با مسیر ثابت `https://eth-mainnet.g.alchemy.com/v2/{apiKey}` استفاده می‌کند. بررسی شامل `eth_chainId = 0x1`، شش رقم اعشار، قرارداد ثابت USDT، موفقیت رسید و قرار گرفتن بلوک در زنجیرهٔ نهایی‌شده است.
- ترون از `https://api.trongrid.io` و هدر `TRON-PRO-API-KEY` استفاده می‌کند. رسید `SUCCESS` باید از مسیر `walletsolidity` دریافت شود و با بلوک، شناسهٔ تراکنش و رویداد انتقال قرارداد ثابت USDT تطبیق داشته باشد.
- کلید هر شبکه در Supabase Vault ذخیره می‌شود. تابع مدیریتی `marketplace_usdt_settings_update` پارامترهای `p_network`، `p_version`، `p_enabled`، `p_address` و `p_api_key` را می‌پذیرد و فقط مالک سامانه مجاز به تغییر آن است. `marketplace_usdt_settings` فقط وجود کلید را با `has_api_key` نشان می‌دهد. کلید خصوصی کیف پول در این اتصال دریافت یا استفاده نمی‌شود.

تابع `supabase/functions/usdt-payments/index.ts` با نام `usdt-payments` و فایل‌های مشترک `usdt-payments.ts` و `usdt-chain.ts` منتشر می‌شود. متغیرهای آن `SUPABASE_URL`، `SUPABASE_SERVICE_ROLE_KEY` و `USDT_ALLOWED_ORIGINS` هستند. برای متغیر آخر، مبدأهای دقیق HTTPS مارکت‌پلیس و مدیریت را با کاما جدا کنید؛ پیش‌فرض فقط نشانی‌های توسعهٔ محلی روی درگاه‌های ۳۰۰۰ و ۳۰۰۱ است. تنظیم `verify_jwt = false` در `supabase/config.toml` با احراز هویت داخل تابع همراه است: اقدام `verify` نشست و مالکیت درخواست را کنترل می‌کند؛ `reconcile_pending` فقط برای مالک سامانه یا کلید سرویس مجاز است و حداکثر پنج درخواست را بررسی می‌کند.

نشانی شرکت میان کاربران مشترک است؛ سامانه برای هر درخواست مبلغ دقیق و یکتا با اختلاف کمتر از ۰٫۰۰۱ تتر و مهلت یک ساعت می‌سازد. مبلغ رسیده به مقصد باید دقیقاً همان عدد باشد. شبکه، قرارداد، مقصد، مبلغ، زمان بلوک، شناسهٔ تراکنش و شمارهٔ رویداد تطبیق داده می‌شوند. تراکنش نهایی‌نشده در انتظار می‌ماند؛ مغایرت، چند انتقال مطابق یا رسید استفاده‌شده موجب شارژ نمی‌شود. `marketplace_usdt_record_proof` فقط مدرک تغییرناپذیر را ثبت و روش بررسی درخواست را اعمال می‌کند. با تنظیمات پیش‌فرض، نتیجه `verification_status = verified` و همچنان در انتظار تأیید مدیر است. فقط `status = credited` نشان می‌دهد موجودی واقعی اضافه شده است.

## برداشت و وضعیت استقرار

درخواست برداشت تومان، مبلغ را از موجودی واقعیِ در دسترس رزرو می‌کند. تأیید مدیر آن را به `awaiting_payout` می‌برد؛ این وضعیت به معنی ارسال وجه بانکی نیست. رد درخواست رزرو را فقط یک بار آزاد می‌کند. موجودی آزمایشی قابل برداشت نیست.

وضعیت ثبت‌شده در ۲۰ اکتبر ۲۰۲۶: مهاجرت‌های `202610190001` تا `202610190003` و تابع `usdt-payments` نصب شده‌اند. نشانی کیف پول شرکت و کلیدهای ارائه‌دهندگان USDT هنوز تنظیم نشده‌اند و تابع `bale-payments` هنوز منتشر نشده است. نصب کد به معنی فعال بودن پذیرش پرداخت یا آزموده شدن پرداخت واقعی نیست. در این مرحله، پرداخت واقعی بله و انتقال واقعی USDT آزموده نشده‌اند.

تست‌های `tests/usdt-chain.test.mjs`، `tests/usdt-payments.test.mjs`، `tests/wallet-funding-api.test.mjs` و `tests/wallet-funding-db.test.mjs` منطق تطبیق، مجوزها، بررسی دستی و جلوگیری از ثبت تکراری را با داده‌های کنترل‌شده بررسی می‌کنند. آزمون واقعی پس از تنظیم مقصد و کلیدهای شرکت انجام می‌شود.
