orderByDesc('id'); \App\DB\Te\TableEngine::create($query, $request) ->initSearch(['desc', 'type']) ->select(['*']) ->export($query); return response()->json($query); } public function show($id) { return response()->json(PargarSyncLog::with('customer')->findOrFail($id)); } public function customerSyncStatus(Request $request) { $panelTotal = Customer::whereNull('deleted_at')->count(); $panelRegistered = Customer::whereNull('deleted_at')->whereNotNull('pargar_account_id')->count(); $panelOnly = $panelTotal - $panelRegistered; $panelOnlyQuery = Customer::whereNull('deleted_at') ->whereNull('pargar_account_id') ->select('id', 'name', 'mobile', 'created_at'); if ($search = $request->input('search')) { $panelOnlyQuery->where(function ($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('mobile', 'like', "%{$search}%"); }); } $panelOnlyList = $panelOnlyQuery->orderBy('id')->paginate(20); $inboundOnlyQuery = PargarSyncLog::query() ->where('type', 'customer') ->where('sync_status', PargarSyncService::STATUS_SUCCESS) ->whereNotNull('pargar_ref') ->latest('id'); $inboundOnlyCount = (clone $inboundOnlyQuery)->count(); $inboundSample = $inboundOnlyQuery->limit(100)->get(['id', 'customer_id', 'pargar_ref', 'created_at']); return response()->json([ 'panel_total' => $panelTotal, 'panel_registered' => $panelRegistered, 'panel_only' => $panelOnly, 'pargar_total' => $panelRegistered + $inboundOnlyCount, 'pargar_only_count' => max(0, $inboundOnlyCount), 'panel_only_list' => $panelOnlyList, 'pargar_only_list' => [ 'data' => $inboundSample->map(fn ($row) => [ 'code' => $row->pargar_ref, 'name' => $row->customer?->name ?? '', 'tel' => $row->customer?->mobile ?? '', 'gid' => null, 'group' => '', ])->values(), 'total' => $inboundOnlyCount, 'current_page' => 1, 'last_page' => 1, ], ]); } public function syncPanelToPargar() { $customers = Customer::whereNull('deleted_at') ->whereNull('pargar_account_id') ->get(['id', 'name', 'mobile']); $success = 0; $failed = 0; $errors = []; foreach ($customers as $customer) { $result = $this->sync()->registerCustomer($customer); if ($result['ok'] ?? false) { $success++; } else { $failed++; $errors[] = [ 'name' => $customer->name, 'mobile' => $customer->mobile, 'error' => $result['message'] ?? '', ]; } } return response()->json([ 'ok' => true, 'success' => $success, 'failed' => $failed, 'errors' => $errors, ]); } public function importFromPargar(Request $request) { $validated = $request->validate([ 'customers' => 'required|array', 'customers.*.code' => 'required', 'customers.*.name' => 'required|string', 'customers.*.tel' => 'nullable|string', ]); $success = 0; $failed = 0; $errors = []; foreach ($validated['customers'] as $item) { $mobile = Customer::normalizeMobile($item['tel'] ?? '') ?? ''; $fullName = trim($item['name']); $accountId = (string) $item['code']; $existing = Customer::whereNull('deleted_at') ->where('pargar_account_id', $accountId) ->first(); if ($existing) { $success++; continue; } if ($mobile !== '') { $byMobile = Customer::findActiveByMobile($mobile); if ($byMobile) { $currentAccount = (string) ($byMobile->pargar_account_id ?? ''); if ($currentAccount !== '' && $currentAccount !== $accountId) { $failed++; $errors[] = [ 'name' => $item['name'], 'code' => $item['code'], 'error' => 'شماره موبایل تکراری است', ]; continue; } $byMobile->pargar_account_id = $accountId; if ($fullName !== '') { $byMobile->fname = $fullName; $byMobile->name = $fullName; } $byMobile->save(); $success++; continue; } } $byAccount = Customer::whereNull('deleted_at') ->where('pargar_account_id', $accountId) ->first(); if ($byAccount) { $failed++; $errors[] = [ 'name' => $item['name'], 'code' => $item['code'], 'error' => 'کد حساب پرگار قبلاً ثبت شده است', ]; continue; } try { $customer = new Customer(); $customer->fname = $fullName; $customer->lname = ''; $customer->name = $fullName; $customer->mobile = $mobile; $customer->active = true; $customer->pargar_account_id = $accountId; $customer->referral_id = $this->uniqueReferralId(); $customer->type = 2; if ($mobile !== '') { $customer->password = $mobile; } $customer->save(); $success++; } catch (\Throwable $e) { $failed++; $errors[] = ['name' => $item['name'], 'code' => $item['code'], 'error' => $e->getMessage()]; } } return response()->json([ 'ok' => true, 'success' => $success, 'failed' => $failed, 'errors' => $errors, ]); } public function rollbackImport(Request $request) { $baseQuery = fn () => Customer::whereNotNull('pargar_account_id') ->where(function ($q) { $q->whereNull('name')->orWhere('name', ''); }); $count = $baseQuery()->count(); $sample = $baseQuery() ->select('id', 'fname', 'name', 'mobile', 'pargar_account_id', 'created_at') ->orderByDesc('id') ->limit(20) ->get(); if ($request->boolean('dry_run')) { return response()->json([ 'dry_run' => true, 'count' => $count, 'sample' => $sample, ]); } $deleted = $baseQuery()->forceDelete(); return response()->json([ 'ok' => true, 'deleted' => $deleted, ]); } public function retrySanad($id) { $log = PargarSyncLog::with('customer')->findOrFail($id); $result = $this->sync()->retry($log); return response()->json($result, ($result['ok'] ?? false) ? 200 : 422); } public function registerCustomer($customerId) { $customer = Customer::findOrFail($customerId); $result = $this->sync()->registerCustomer($customer); return response()->json($result, ($result['ok'] ?? false) ? 200 : 422); } public function syncCustomerWallet($customerId) { if (! app(ConfigService::class)->isPargarAccounting()) { return response()->json([ 'ok' => false, 'message' => 'حسابداری پرگار فعال نیست', ], 422); } $customer = Customer::findOrFail($customerId); if (trim((string) ($customer->pargar_account_id ?? '')) === '') { return response()->json([ 'ok' => false, 'message' => 'این مشتری کد حساب پرگار ندارد', ], 422); } $result = app(PargarInboundWalletService::class)->syncWalletFromPargar($customer); $appliedDocs = (int) ($result['documents']['applied'] ?? 0); $appliedMande = (bool) ($result['mande']['applied'] ?? false); $mandeMessage = (string) ($result['mande']['message'] ?? ''); $messages = []; if ($appliedDocs > 0) { $messages[] = "{$appliedDocs} سند از پرگار اعمال شد"; } if ($appliedMande) { $messages[] = 'ماندهٔ پرگار روی کیف اعمال شد'; } if ($mandeMessage !== '' && ! $appliedMande) { $messages[] = $mandeMessage; } return response()->json([ 'ok' => $appliedDocs > 0 || $appliedMande, 'message' => $messages !== [] ? implode(' — ', $messages) : 'سند قابل‌اعمالی یافت نشد', 'result' => $result, ], $appliedDocs > 0 || $appliedMande ? 200 : 422); } private function uniqueReferralId(): string { do { $referral = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyz'), 0, 4); } while (Customer::where('referral_id', $referral)->exists()); return $referral; } }