diff --git a/app/Http/Controllers/Finance/FinanceController.php b/app/Http/Controllers/Finance/FinanceController.php index 2b45631..31167e7 100644 --- a/app/Http/Controllers/Finance/FinanceController.php +++ b/app/Http/Controllers/Finance/FinanceController.php @@ -3,18 +3,8 @@ namespace App\Http\Controllers\Finance; use App\Http\Controllers\Controller; -use App\Http\Controllers\Admin\TahesabController; -use App\Models\Customer; -use App\Models\Order; -use App\Models\Price; -use App\Models\Product; use App\Models\TransactionsAdmin; -use App\Models\User; -use App\Models\Withdraw; -use App\Models\Tahesab; -use App\Services\TahesabSyncService; use App\DB\Te\TableEngine; -use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -25,151 +15,21 @@ use Rooyesh\Wallet\models\Wallet; class FinanceController extends Controller { + /** + * دفترکل داخلی: همه رویدادهای مالی (معامله / شارژ / پاداش و …). + * مستقل از اتصال به حسابداری بیرونی — برای همه اپ‌ها نمایان است. + */ public function fall(Request $request) { - $transactions_admins = TransactionsAdmin::with(['withdraw','order',"user",'customerTo','customer']); + $transactions_admins = TransactionsAdmin::with(['withdraw', 'order', 'user', 'customerTo', 'customer']); TableEngine::create($transactions_admins, $request) ->initSearch(['price']) ->select(['*']) ->export($transactions_admins); - if (isset($transactions_admins['rows']) && is_array($transactions_admins['rows']) && $this->Config('send_to_tahesab') === 'true') { - $this->enrichRowsWithTahesab($transactions_admins['rows']); - } - return response()->json($transactions_admins); } - /** - * هر ردیف دفترکل را با وضعیت سند ته‌حساب مرتبط غنی می‌کند. - * لینک: ابتدا از طریق withdraw_id (کیف‌پول/پاداش) و سپس order_id (معامله). - * - * @param array> $rows با ارجاع تغییر می‌کند - */ - private function enrichRowsWithTahesab(array &$rows): void - { - $withdrawIds = collect($rows)->pluck('withdraw_id')->filter()->unique()->values()->all(); - $orderIds = collect($rows)->pluck('order_id')->filter()->unique()->values()->all(); - - if ($withdrawIds === [] && $orderIds === []) { - return; - } - - $tahesabByWithdraw = $withdrawIds === [] - ? collect() - : Tahesab::query()->whereIn('withdraw_id', $withdrawIds) - ->orderByDesc('id')->get()->unique('withdraw_id')->keyBy('withdraw_id'); - - $tahesabByOrder = $orderIds === [] - ? collect() - : Tahesab::query()->whereIn('order_id', $orderIds) - ->orderByDesc('id')->get()->unique('order_id')->keyBy('order_id'); - - foreach ($rows as &$row) { - $tahesab = $tahesabByWithdraw->get($row['withdraw_id'] ?? null) - ?? $tahesabByOrder->get($row['order_id'] ?? null); - - if (! $tahesab) { - // ردیف دفترکل بدون سند ته‌حساب — یعنی هنوز به حسابداری ارسال نشده - $row['tahesab_record_id'] = null; - $row['tahesab_sync_status'] = TahesabSyncService::STATUS_PENDING; - $row['tahesab_failed_id'] = null; - continue; - } - - $row['tahesab_record_id'] = $tahesab->id; - $row['tahesab_sync_status'] = $tahesab->sync_status - ?? (empty($tahesab->tahesab_id) ? TahesabSyncService::STATUS_PENDING : TahesabSyncService::STATUS_SUCCESS); - - if (empty($tahesab->tahesab_id) || $row['tahesab_sync_status'] === TahesabSyncService::STATUS_FAILED) { - $row['tahesab_failed_id'] = $tahesab->id; - } - } - unset($row); - } - - /** - * سینک یک ردیف دفترکل با حسابداری (فعلاً ته‌حساب). - * اگر سند ته‌حساب مرتبط موجود باشد → retry؛ وگرنه از روی منبع (معامله) ساخته و ارسال می‌شود. - */ - public function sync(int $id) - { - if ($this->Config('send_to_tahesab') !== 'true') { - throw new UnprocessableEntityHttpException('حسابداری ته‌حساب فعال نیست'); - } - - $row = TransactionsAdmin::find($id); - if (! $row) { - throw new UnprocessableEntityHttpException('سند دفترکل یافت نشد'); - } - - $tahesab = $this->findLinkedTahesab($row); - - if ($tahesab) { - $result = app(TahesabSyncService::class)->retry($tahesab); - $status = ($result['ok'] ?? false) ? 200 : 422; - - return response()->json($result, $status); - } - - // سند ته‌حساب وجود ندارد — اگر معامله است، از روی سفارش بساز و ارسال کن - if ($row->order_id) { - return $this->syncTradeFromOrder((int) $row->order_id); - } - - throw new UnprocessableEntityHttpException( - 'برای این ردیف سند ته‌حسابی یافت نشد و امکان ساخت خودکار آن وجود ندارد' - ); - } - - private function findLinkedTahesab(TransactionsAdmin $row): ?Tahesab - { - if ($row->withdraw_id) { - $byWithdraw = Tahesab::where('withdraw_id', $row->withdraw_id)->orderByDesc('id')->first(); - if ($byWithdraw) { - return $byWithdraw; - } - } - - if ($row->order_id) { - return Tahesab::where('order_id', $row->order_id)->orderByDesc('id')->first(); - } - - return null; - } - - private function syncTradeFromOrder(int $orderId) - { - $order = Order::find($orderId); - if (! $order) { - throw new UnprocessableEntityHttpException('سفارش مرتبط یافت نشد'); - } - - $product = Product::find($order->product_id); - if (! $product) { - throw new UnprocessableEntityHttpException('محصول سفارش یافت نشد — امکان ساخت سند ته‌حساب نیست'); - } - - $data = [ - 'customer_id' => $order->customer_id, - 'direction' => (int) $order->direction, - 'price' => $order->price, - 'total_price' => $order->total_price, - 'amount' => $order->amount, - 'pay_at' => $order->pay_at ?? $order->created_at, - 'product' => $product, - 'order' => ['id' => $order->id], - ]; - - $result = app(TahesabController::class)->storeTrade($data); - $ok = $result !== false && ! is_string($result); - - return response()->json([ - 'ok' => $ok, - 'message' => $ok ? 'سند معامله در ته‌حساب ثبت شد' : (is_string($result) ? $result : 'ارسال به ته‌حساب ناموفق بود'), - ], $ok ? 200 : 422); - } - public function index() { $tallaPrice = Price::latest()->first(); diff --git a/database/sql/deploy_settings_const.sql b/database/sql/deploy_settings_const.sql index 7c5cc78..07941a1 100644 --- a/database/sql/deploy_settings_const.sql +++ b/database/sql/deploy_settings_const.sql @@ -14,8 +14,8 @@ -- اصول: -- • چند بار قابل اجرا (idempotent) -- • value / is_active ردیف‌های موجود دست نخورده --- • can_edit هر deploy از این فایل override می‌شود (استاندارد مشترک همه پروژه‌ها) --- • فقط INSERT برای کلیدهای جدید + به‌روز type / title_fa / description +-- • can_edit / title_fa / description هر deploy از این فایل override می‌شوند (استاندارد مشترک) +-- • فقط INSERT برای کلیدهای جدید + به‌روز type -- • schema (جدول/ستون) فقط با migrate — نه این فایل -- -- قبل از اجرا: USE `نام_دیتابیس`; + بکاپ @@ -477,7 +477,7 @@ SELECT 'price_from_nasiryan', 'false', 'قیمت از نصیریان', 1, 0, NUL WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'price_from_nasiryan' LIMIT 1); -- ============================================================================= --- عنوان فارسی (فقط اگر title_fa خالی باشد) +-- عنوان فارسی — backfill اولیه (فقط اگر title_fa خالی باشد؛ override نهایی در انتهای فایل) -- ============================================================================= -- backfill عنوان فارسی کلیدهای قدیمی (فقط اگر title_fa خالی/NULL باشد) @@ -1057,6 +1057,132 @@ WHERE `key` IN ( 'montzar_order_response', 'montzar_last_product_log' ); +-- --------------------------------------------------------------------------- +-- title_fa — استاندارد مشترک (override؛ value / is_active دست نمی‌خورند) +-- --------------------------------------------------------------------------- + +UPDATE `settings` SET `title_fa` = 'آدرس پنل ادمین' WHERE `key` = 'admin_url'; +UPDATE `settings` SET `title_fa` = 'لینک دانلود اپ اندروید' WHERE `key` = 'apk_download_link'; +UPDATE `settings` SET `title_fa` = 'آدرس اپ (کاربر)' WHERE `key` = 'app_url'; +UPDATE `settings` SET `title_fa` = 'فعال‌سازی خودکار کاربر' WHERE `key` = 'auto_active_customer'; +UPDATE `settings` SET `title_fa` = 'آدرس پایه' WHERE `key` = 'bace_url'; +UPDATE `settings` SET `title_fa` = 'حذف مشتری از تراز' WHERE `key` = 'balance_report_exclude_customer_id'; +UPDATE `settings` SET `title_fa` = 'توکن بات بله' WHERE `key` = 'bale_bot_token'; +UPDATE `settings` SET `title_fa` = 'نمایش بنرها' WHERE `key` = 'banner_enabled'; +UPDATE `settings` SET `title_fa` = 'سود خرید نمایش' WHERE `key` = 'buy_fee'; +UPDATE `settings` SET `title_fa` = 'پیامک شارژ ادمین' WHERE `key` = 'charge_notif'; +UPDATE `settings` SET `title_fa` = 'UUID نمودار Zaarbox' WHERE `key` = 'chart_id'; +UPDATE `settings` SET `title_fa` = 'نمودار از داده خود سایت' WHERE `key` = 'chart_use_local_data'; +UPDATE `settings` SET `title_fa` = 'بستن خودکار خارج از ساعت کاری' WHERE `key` = 'close_price'; +UPDATE `settings` SET `title_fa` = 'رنگ اصلی' WHERE `key` = 'color_primary'; +UPDATE `settings` SET `title_fa` = 'رنگ ثانویه' WHERE `key` = 'color_secondary'; +UPDATE `settings` SET `title_fa` = 'پیشوند شماره حواله (پرگار)' WHERE `key` = 'default_vc_number'; +UPDATE `settings` SET `title_fa` = 'شماره تماس جهت پشتیبانی واریز' WHERE `key` = 'deposit_sms_support_number'; +UPDATE `settings` SET `title_fa` = 'کمترین قیمت امروز' WHERE `key` = 'down_price'; +UPDATE `settings` SET `title_fa` = 'ساعت پایان' WHERE `key` = 'endDay'; +UPDATE `settings` SET `title_fa` = 'فعال‌سازی API سفارش خارجی (get_wallet / order)' WHERE `key` = 'external_order_api_enabled'; +UPDATE `settings` SET `title_fa` = 'کارمزد (قدیمی — درصد)' WHERE `key` = 'fee'; +UPDATE `settings` SET `title_fa` = 'کارمزد ریالی سفارش (legacy)' WHERE `key` = 'fee_cash'; +UPDATE `settings` SET `title_fa` = 'تعداد سفارش اول بدون کارمزد' WHERE `key` = 'fee_free'; +UPDATE `settings` SET `title_fa` = 'درصد کارمزد سفارش' WHERE `key` = 'fee_service_charge_percentage'; +UPDATE `settings` SET `title_fa` = 'اختلاف پایه نمایش' WHERE `key` = 'fee_single'; +UPDATE `settings` SET `title_fa` = 'پاداش معرف‌شونده' WHERE `key` = 'gift_for_referral'; +UPDATE `settings` SET `title_fa` = 'پاداش معرف' WHERE `key` = 'gift_for_referrer'; +UPDATE `settings` SET `title_fa` = 'پیامک گروهی' WHERE `key` = 'group_sms'; +UPDATE `settings` SET `title_fa` = 'چت پشتیبانی' WHERE `key` = 'has_chat'; +UPDATE `settings` SET `title_fa` = 'صفحه کسب درآمد' WHERE `key` = 'has_page_earn_money'; +UPDATE `settings` SET `title_fa` = 'صفحه صندوق' WHERE `key` = 'has_page_fund'; +UPDATE `settings` SET `title_fa` = 'صفحه مجوزها' WHERE `key` = 'has_page_permission'; +UPDATE `settings` SET `title_fa` = 'صفحه طلای فیزیکی' WHERE `key` = 'has_page_physical_gold'; +UPDATE `settings` SET `title_fa` = 'صفحه هشدار قیمت' WHERE `key` = 'has_page_price_trigger'; +UPDATE `settings` SET `title_fa` = 'متن دعوتنامه اشتراک‌گذاری' WHERE `key` = 'invite_link_text'; +UPDATE `settings` SET `title_fa` = 'حالت فروشگاهی' WHERE `key` = 'is_store'; +UPDATE `settings` SET `title_fa` = 'تأیید کارت بانکی با جیبیت' WHERE `key` = 'jibit_verification'; +UPDATE `settings` SET `title_fa` = 'کلید داخلی اپ' WHERE `key` = 'key'; +UPDATE `settings` SET `title_fa` = 'لوگوی صفحه ورود' WHERE `key` = 'logo_login'; +UPDATE `settings` SET `title_fa` = 'لوگوی ثبت‌نام' WHERE `key` = 'logo_register'; +UPDATE `settings` SET `title_fa` = 'نام فلز اصلی (ادمین)' WHERE `key` = 'main_metal'; +UPDATE `settings` SET `title_fa` = 'محصول آبشده' WHERE `key` = 'main_product'; +UPDATE `settings` SET `title_fa` = 'قیمت از محصول (legacy)' WHERE `key` = 'main_product_price'; +UPDATE `settings` SET `title_fa` = 'محصولات متصل به کیف اصلی' WHERE `key` = 'main_wallet_products'; +UPDATE `settings` SET `title_fa` = 'عنوان فلز در UI' WHERE `key` = 'metal_type'; +UPDATE `settings` SET `title_fa` = 'حداقل اولین خرید (ریال)' WHERE `key` = 'min_first_buy'; +UPDATE `settings` SET `title_fa` = 'حداقل برداشت (ریال)' WHERE `key` = 'min_withdraw'; +UPDATE `settings` SET `title_fa` = 'حداقل فروش' WHERE `key` = 'minimum_sell'; +UPDATE `settings` SET `title_fa` = 'نام فروشگاه در درگاه' WHERE `key` = 'montify_name'; +UPDATE `settings` SET `title_fa` = 'آدرس سرور همکار' WHERE `key` = 'montzar_base_url'; +UPDATE `settings` SET `title_fa` = 'بسته بودن همکار' WHERE `key` = 'montzar_closed'; +UPDATE `settings` SET `title_fa` = 'اختلاف قیمت همکار' WHERE `key` = 'montzar_diff'; +UPDATE `settings` SET `title_fa` = 'لاگ محصول همکار' WHERE `key` = 'montzar_last_product_log'; +UPDATE `settings` SET `title_fa` = 'قیمت لحظه‌ای همکار' WHERE `key` = 'montzar_live_price'; +UPDATE `settings` SET `title_fa` = 'مظنه همکار' WHERE `key` = 'montzar_mazaneh'; +UPDATE `settings` SET `title_fa` = 'موبایل API همکار' WHERE `key` = 'montzar_mobile'; +UPDATE `settings` SET `title_fa` = 'باز بودن خرید همکار' WHERE `key` = 'montzar_open_buy'; +UPDATE `settings` SET `title_fa` = 'باز بودن فروش همکار' WHERE `key` = 'montzar_open_sell'; +UPDATE `settings` SET `title_fa` = 'پاسخ سفارش همکار' WHERE `key` = 'montzar_order_response'; +UPDATE `settings` SET `title_fa` = 'رمز API همکار' WHERE `key` = 'montzar_password'; +UPDATE `settings` SET `title_fa` = 'قیمت از همکار (montzar)' WHERE `key` = 'montzar_price'; +UPDATE `settings` SET `title_fa` = 'کد محصول همکار' WHERE `key` = 'montzar_product_id'; +UPDATE `settings` SET `title_fa` = 'توکن همکار (خودکار)' WHERE `key` = 'montzar_token'; +UPDATE `settings` SET `title_fa` = 'مظنه خرید همکار' WHERE `key` = 'montzar_truly_buy_mazaneh'; +UPDATE `settings` SET `title_fa` = 'مظنه فروش همکار' WHERE `key` = 'montzar_truly_sell_mazaneh'; +UPDATE `settings` SET `title_fa` = 'نام انگلیسی اپ' WHERE `key` = 'name_en'; +UPDATE `settings` SET `title_fa` = 'نام فارسی اپ' WHERE `key` = 'name_fa'; +UPDATE `settings` SET `title_fa` = 'شناسه کلاینت API خارجی (X-Client-Id)' WHERE `key` = 'node_client_id'; +UPDATE `settings` SET `title_fa` = 'کلید امضای HMAC API خارجی' WHERE `key` = 'node_shared_secret'; +UPDATE `settings` SET `title_fa` = 'ثبت‌نام باز' WHERE `key` = 'open_register'; +UPDATE `settings` SET `title_fa` = 'customer_id fin' WHERE `key` = 'payping_fin_customer_id'; +UPDATE `settings` SET `title_fa` = 'همگام‌سازی fin' WHERE `key` = 'payping_fin_sync_enabled'; +UPDATE `settings` SET `title_fa` = 'توکن fin' WHERE `key` = 'payping_fin_token'; +UPDATE `settings` SET `title_fa` = 'URL fin' WHERE `key` = 'payping_fin_url'; +UPDATE `settings` SET `title_fa` = 'item تکی (legacy)' WHERE `key` = 'payping_gateway_item'; +UPDATE `settings` SET `title_fa` = 'لیست item (چرخشی)' WHERE `key` = 'payping_gateway_items'; +UPDATE `settings` SET `title_fa` = 'نام gateway درگاه' WHERE `key` = 'payping_gateway_name'; +UPDATE `settings` SET `title_fa` = 'گرد کردن مبلغ به تومان' WHERE `key` = 'payping_round_toman'; +UPDATE `settings` SET `title_fa` = 'آدرس شروع درگاه' WHERE `key` = 'payping_start_url'; +UPDATE `settings` SET `title_fa` = 'برداشت ناموفق سخت‌گیرانه' WHERE `key` = 'payping_strict_failed_withdraw'; +UPDATE `settings` SET `title_fa` = 'آدرس تأیید درگاه' WHERE `key` = 'payping_verify_url'; +UPDATE `settings` SET `title_fa` = 'تاریخ min/max روز' WHERE `key` = 'price_extreme_date'; +UPDATE `settings` SET `title_fa` = 'قیمت از نصیریان' WHERE `key` = 'price_from_nasiryan'; +UPDATE `settings` SET `title_fa` = 'منبع قیمت' WHERE `key` = 'price_provider'; +UPDATE `settings` SET `title_fa` = 'API سود طلا' WHERE `key` = 'profit_gold_api_enabled'; +UPDATE `settings` SET `title_fa` = 'مقدار پاداش معرف' WHERE `key` = 'referral_bonus_amount'; +UPDATE `settings` SET `title_fa` = 'تعداد معرف برای هدیه' WHERE `key` = 'referral_count_for_gift'; +UPDATE `settings` SET `title_fa` = 'کد معرف اجباری' WHERE `key` = 'referral_id'; +UPDATE `settings` SET `title_fa` = 'محدودیت دعوت' WHERE `key` = 'referral_limit'; +UPDATE `settings` SET `title_fa` = 'تأیید کدملی/موبایل در ثبت‌نام' WHERE `key` = 'register_jibit_verify'; +UPDATE `settings` SET `title_fa` = 'پیام پاداش در SMS ثبت‌نام' WHERE `key` = 'register_referral_bonus_message'; +UPDATE `settings` SET `title_fa` = 'SMS به معرف هنگام ثبت‌نام' WHERE `key` = 'register_referral_sms_to_referrer'; +UPDATE `settings` SET `title_fa` = 'سود فروش نمایش' WHERE `key` = 'sell_fee'; +UPDATE `settings` SET `title_fa` = 'ارسال به ته‌حساب' WHERE `key` = 'send_to_tahesab'; +UPDATE `settings` SET `title_fa` = 'آدرس API سرور' WHERE `key` = 'server_url'; +UPDATE `settings` SET `title_fa` = 'کارمزد درصدی (alias)' WHERE `key` = 'service_charge_percentage'; +UPDATE `settings` SET `title_fa` = 'نمایش آخرین قیمت ذخیره‌شده' WHERE `key` = 'show_last_price'; +UPDATE `settings` SET `title_fa` = 'مسیر SSE قیمت' WHERE `key` = 'sse_path'; +UPDATE `settings` SET `title_fa` = 'ساعت شروع' WHERE `key` = 'startDay'; +UPDATE `settings` SET `title_fa` = 'وضعیت فروشگاه' WHERE `key` = 'store_status'; +UPDATE `settings` SET `title_fa` = 'پیام‌رسان پشتیبانی' WHERE `key` = 'support_messenger'; +UPDATE `settings` SET `title_fa` = 'شناسه پشتیبانی پیام‌رسان' WHERE `key` = 'support_messenger_id'; +UPDATE `settings` SET `title_fa` = 'متن پشتیبانی پیام‌رسان' WHERE `key` = 'support_messenger_text'; +UPDATE `settings` SET `title_fa` = 'حساب بانکی ته‌حساب' WHERE `key` = 'tahesab_bank_account'; +UPDATE `settings` SET `title_fa` = 'نام دیتابیس ته‌حساب' WHERE `key` = 'tahesab_db'; +UPDATE `settings` SET `title_fa` = 'آدرس IP سرور ته‌حساب' WHERE `key` = 'tahesab_host'; +UPDATE `settings` SET `title_fa` = 'پورت سرور ته‌حساب' WHERE `key` = 'tahesab_port'; +UPDATE `settings` SET `title_fa` = 'توکن ته‌حساب' WHERE `key` = 'tahesab_token'; +UPDATE `settings` SET `title_fa` = 'توکن بات تلگرام' WHERE `key` = 'telegram_bot_token'; +UPDATE `settings` SET `title_fa` = 'متن درباره ما' WHERE `key` = 'text_about'; +UPDATE `settings` SET `title_fa` = 'متن قوانین' WHERE `key` = 'text_rule'; +UPDATE `settings` SET `title_fa` = 'عنوان favicon' WHERE `key` = 'title_fav'; +UPDATE `settings` SET `title_fa` = 'عنوان PWA' WHERE `key` = 'title_pwa'; +UPDATE `settings` SET `title_fa` = 'واحد وزن دارایی و معاملات' WHERE `key` = 'unit'; +UPDATE `settings` SET `title_fa` = 'بیشترین قیمت امروز' WHERE `key` = 'up_price'; +UPDATE `settings` SET `title_fa` = 'قیمت لحظه‌ای (SSE)' WHERE `key` = 'wss_enabled'; +UPDATE `settings` SET `title_fa` = 'آدرس trigger وب‌سوکت (سرور)' WHERE `key` = 'wss_link'; +UPDATE `settings` SET `title_fa` = 'مسیر WebSocket قیمت' WHERE `key` = 'wss_path'; +UPDATE `settings` SET `title_fa` = 'مسیر trigger برادکست' WHERE `key` = 'wss_trigger_path'; +UPDATE `settings` SET `title_fa` = 'آدرس API تابلو Zaarbox' WHERE `key` = 'zaarbox_api_url'; +UPDATE `settings` SET `title_fa` = 'شناسه ردیف تابلو (key یا UUID)' WHERE `key` = 'zaarbox_price_key'; + -- --------------------------------------------------------------------------- -- can_edit — استاندارد مشترک (override؛ value دست نمی‌خورد) -- --------------------------------------------------------------------------- diff --git a/routes/admin.php b/routes/admin.php index 0eb32a0..ebdce6d 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -134,7 +134,6 @@ Route::middleware('auth:user')->group(function (){ Route::post('finance', [FinanceController::class, 'fall']); - Route::post('finance/{id}/sync', [FinanceController::class, 'sync']); //dashboard