with = []; $this->select = ['*']; $search=['name','mobile']; $this->query = Customer::with($this->with,'wallet')->where('is_archive',false)->where('type',1); // $this->query = Customer::where('is_archive',false)->get(); parent::__construct(Customer::class, $this->with, $this->select, 'customer', $this->query, $search); } /** * @param $id * @return \Illuminate\Http\JsonResponse */ public function listUser(){ $balanceService = app(WalletBalanceService::class); $catalogMetalIds = $balanceService->catalogMetalIds(); $users = Customer::with(['wallet'])->select('id', 'name', 'mobile', 'type')->get()->map(function ($user) use ($balanceService, $catalogMetalIds) { $wallets = collect($user->wallet ?? []); $ownerType = (int) $user->type; $user->wallet_cash = $balanceService->mainWalletCash($wallets, $ownerType); $metalMap = $balanceService->buildCustomerWalletMetalDisplayMap($wallets, $catalogMetalIds); $user->wallet_gold = array_sum($metalMap); return $user; }); return response()->json($users); } /** * مشتریان با SSE فعال در بازهٔ آنلاین بودن (last_seen_at تازه). */ public function onlineList() { $threshold = now()->subSeconds(CustomerPresenceService::ONLINE_THRESHOLD_SECONDS); $rows = Customer::query() ->with('referral') ->where('is_archive', false) ->whereNotNull('last_seen_at') ->where('last_seen_at', '>=', $threshold) ->orderByDesc('last_seen_at') ->get(); return response()->json([ 'count' => $rows->count(), 'online_within_seconds' => CustomerPresenceService::ONLINE_THRESHOLD_SECONDS, 'rows' => $rows, ]); } /** * حضور سبک برای چت پشتیبانی: chat_room_id / chat_user_id → last_seen_at * (همان منبع آنلاین بودن صفحه‌ی کاربران آنلاین). */ public function chatPresence() { $hasRoom = \Schema::hasColumn('customers', 'chat_room_id'); $hasUser = \Schema::hasColumn('customers', 'chat_user_id'); if (! $hasRoom && ! $hasUser) { return response()->json([ 'online_within_seconds' => CustomerPresenceService::ONLINE_THRESHOLD_SECONDS, 'rows' => [], ]); } $columns = ['id', 'last_seen_at']; if ($hasRoom) { $columns[] = 'chat_room_id'; } if ($hasUser) { $columns[] = 'chat_user_id'; } $query = Customer::query() ->where('is_archive', false) ->select($columns); $query->where(function ($q) use ($hasRoom, $hasUser) { if ($hasRoom) { $q->orWhere(function ($inner) { $inner->whereNotNull('chat_room_id')->where('chat_room_id', '!=', ''); }); } if ($hasUser) { $q->orWhere(function ($inner) { $inner->whereNotNull('chat_user_id')->where('chat_user_id', '!=', ''); }); } }); return response()->json([ 'online_within_seconds' => CustomerPresenceService::ONLINE_THRESHOLD_SECONDS, 'rows' => $query->get(), ]); } public function updateAdmin(Request $request , $id) { $data = $request->all(); if (isset($data['mobile']) && !is_null($data['mobile'])){ $data['mobile'] = Customer::normalizeMobile($data['mobile']); Customer::assertMobileUnique($data['mobile'], (int) $id); } if (array_key_exists('pargar_account_id', $data)) { $data['pargar_account_id'] = $this->normalizeAndAssertUniqueAccountingCode( $data['pargar_account_id'], 'pargar_account_id', (int) $id ); } if (array_key_exists('moshtari_code', $data)) { $data['moshtari_code'] = $this->normalizeAndAssertUniqueAccountingCode( $data['moshtari_code'], 'moshtari_code', (int) $id ); } if (isset($data['gold'])){ $user = Customer::find($id); if ($user) { $user->gold = $data['gold']; $user->save(); $user["g"]=true; } } $user["u"] = Customer::findOrFail($id)->update($data); return response()->json($user); } /** * خالی / 0 / -1 → null؛ در غیر این صورت یکتا بودن کد بین مشتریان فعال. */ private function normalizeAndAssertUniqueAccountingCode(mixed $value, string $column, int $customerId): ?string { if ($value === null) { return null; } $code = trim((string) $value); if ($code === '' || in_array($code, ['0', '-1'], true)) { return null; } $exists = Customer::whereNull('deleted_at') ->where($column, $code) ->where('id', '!=', $customerId) ->exists(); if ($exists) { throw new UnprocessableEntityHttpException('این کد حسابداری قبلاً برای مشتری دیگری ثبت شده است'); } return $code; } public function referrals(Request $request,$customer_id) { $customer_referral_id = Customer::where("id",$customer_id)->first()->referral_id; $query_table = Customer::where("referral_to_id",$customer_referral_id); TableEngine::create($query_table, $request) ->initSearch($this->search) ->select(['*',Customer::$SELECT_TYPE_STR]) ->export($query_table); return response()->json($query_table); } public function funds(Request $request,$customer_id) { $mainWalletProductIds = app(\App\Services\ConfigService::class)->mainWalletProductIds(); $balanceService = app(WalletBalanceService::class); $catalogMetalIds = $balanceService->catalogMetalIds(); $mainWalletMetalId = $balanceService->resolveMainWalletMetalId(); $productCols = implode(',', self::WALLET_PRODUCT_COLUMNS); // فقط کیف محصول‌ها (نه کیف اصلی) — هر ردیف = موجودی واقعی یک محصول/فلز $query_table = Wallet::with([ 'product' => static function ($q) use ($productCols) { $q->withTrashed()->select(explode(',', $productCols)); }, ]) ->where('owner', $customer_id) ->whereNotNull('product_id'); if ($mainWalletProductIds !== []) { // کیف‌های قدیمیِ محصولات متصل به کیف اصلی نمایش داده نمی‌شوند $query_table->whereNotIn('product_id', $mainWalletProductIds); } TableEngine::create($query_table, $request) ->initSearch($this->search) ->select(['id', 'owner', 'cash', 'gold', 'fund_id', 'product_id', 'created_at', 'updated_at']) ->export($query_table); // محصولات متصل به کیف اصلی: یک ردیف نماینده با موجودی کیف اصلی if ($mainWalletProductIds !== []) { $representative = null; foreach ($mainWalletProductIds as $pid) { $representative = \App\Models\Product::withTrashed() ->select(self::WALLET_PRODUCT_COLUMNS) ->find($pid); if ($representative) { break; } } $mainWallet = Wallet::where('owner', $customer_id) ->whereNull('fund_id') ->whereNull('product_id') ->first(); if ($representative && $mainWallet) { $mainRow = [ 'id' => $mainWallet->id, 'owner' => (int) $customer_id, 'cash' => 0, 'gold' => (float) $mainWallet->gold, 'fund_id' => null, 'product_id' => (int) $representative->id, 'created_at' => $mainWallet->created_at, 'updated_at' => $mainWallet->updated_at, 'product' => $representative, 'is_main_wallet' => true, ]; $query_table['rows'] = collect($query_table['rows'] ?? [])->prepend($mainRow)->values(); $query_table['query']['total'] = (int) ($query_table['query']['total'] ?? 0) + 1; } } if (isset($query_table['rows'])) { foreach ($query_table['rows'] as &$row) { $balanceService->enrichWalletTableRow($row, $catalogMetalIds, $mainWalletMetalId); // اگر eager-load محصول نیامده بود، از lookup پر کن $productId = (int) (is_array($row) ? ($row['product_id'] ?? 0) : ($row->product_id ?? 0)); $hasProduct = is_array($row) ? ! empty($row['product']) : ! empty($row->product); if ($productId > 0 && ! $hasProduct) { $product = \App\Models\Product::withTrashed() ->select(self::WALLET_PRODUCT_COLUMNS) ->find($productId); if ($product) { if (is_array($row)) { $row['product'] = $product; } else { $row->setRelation('product', $product); } $balanceService->enrichWalletTableRow($row, $catalogMetalIds, $mainWalletMetalId); } } } unset($row); } return response()->json($query_table); } public function archive($id){ $query = Customer::findOrFail($id); $query->update([ 'is_archive'=>!$query->is_archive ]); return response()->json(true); } public function tableWallets(Request $request){ $productSelect = 'product:'.implode(',', self::WALLET_PRODUCT_COLUMNS); $query_table = Customer::with(['wallet.'.$productSelect, 'referral'])->where('is_archive', false); TableEngine::create($query_table, $request) ->initSearch($this->search) ->select(['*',Customer::$SELECT_TYPE_STR]) ->export($query_table); $balanceService = app(WalletBalanceService::class); $balanceReport = app(BalanceReportService::class); $catalogMetalIds = $balanceService->catalogMetalIds(); $query_table['catalogMetals'] = $balanceReport->catalogMetalsMeta(); if (isset($query_table['rows'])) { $query_table['rows'] = collect($query_table['rows'])->map(function ($row) use ($balanceService, $catalogMetalIds) { $wallets = collect($row['wallet'] ?? []); $row['wallet_cash'] = $balanceService->mainWalletCash($wallets, (int) ($row['type'] ?? 0)); $metalMap = $balanceService->buildCustomerWalletMetalDisplayMap($wallets, $catalogMetalIds); $row['wallet_metal_gold'] = $metalMap; foreach ($catalogMetalIds as $metalId) { $row['wallet_metal_gold_' . $metalId] = $metalMap[(string) $metalId] ?? 0.0; } $row['wallet_gold'] = array_sum($metalMap); return $row; })->values(); } return response()->json($query_table); } public function assetsSummary($customerId, AssetSummaryService $assetSummaryService) { $customer = Customer::findOrFail($customerId); return response()->json( $assetSummaryService->buildForCustomer((int) $customer->id, (int) $customer->type, true) ); } public function archiveTable(Request $request) { $query_table = Customer::with($this->with)->where("is_archive",true)/*->where('type',1)*/; TableEngine::create($query_table, $request) ->initSearch($this->search) ->select($this->select) ->export($query_table); return response()->json($query_table); } /** * @param $id * @return \Illuminate\Http\JsonResponse */ public function active($id){ $query = Customer::findOrFail($id); $active = !$query->active; $query->update([ 'active'=>!$query->active ]); if ($active){ $message ='اکانت شما توسط کارشناس سیستم تایید شد '."\n". 'با رفتن به لینک زیر وارد حساب کاربری خود شوید'."\n". self::publicSiteUrl(request())."\n". 'با تشکر'.$this->Config('name_fa'); } else{ $message ='اکانت شما توسط کارشناس سیستم غیر فعال شد '."\n". 'با کارشناسان ما تماس بگیرید'."\n". 'با تشکر'.$this->Config('name_fa'); } $this->Send($query->mobile,$message); return response()->json(true); } public function changeTradeActive($id){ $query = Customer::findOrFail($id); $query->update([ 'trade_active'=>!$query->trade_active ]); return response()->json(true); } public function changeConditionalOrderActive($id) { $query = Customer::findOrFail($id); $query->update([ 'conditional_order_active' => ! $query->conditional_order_active, ]); return response()->json([ 'conditional_order_active' => (bool) $query->fresh()->conditional_order_active, ]); } public function updateConditionalOrderLimit(Request $request, $id) { $query = Customer::findOrFail($id); $data = $request->validate([ 'conditional_order_limit' => 'nullable|integer|min:1', ]); $query->update([ 'conditional_order_limit' => $data['conditional_order_limit'] ?? null, ]); return response()->json([ 'conditional_order_limit' => $query->fresh()->conditional_order_limit, ]); } // single customer------------------- public function singleArchiveTable(Request $request) { $query_table = Customer::with($this->with)->where("is_archive",true)->where('type',2); TableEngine::create($query_table, $request) ->initSearch($this->search) ->select($this->select) ->export($query_table); return response()->json($query_table); } public function singleCustomerTable(Request $request) { $query_table = Customer::with($this->with)->where("is_archive",false)->where('type',2); TableEngine::create($query_table, $request) ->initSearch($this->search) ->select($this->select) ->export($query_table); return response()->json($query_table); } public function MakeValidByAdmin(Request $request,$id) { $customer = Customer::with('referral')->where('id', $id)->first(); if ($customer->is_legal == 2 or $customer->is_legal == 3){ return response()->json(true); } $customer->is_legal = 2; $customer->save(); if ($this->Config('has_page_earn_money') == 'true') { $referrer = $customer->referrer(); if ( $referrer && Customer::where('referral_to_id', $referrer->referral_id)->where('is_legal', '!=', 0)->count() < 4 ) { $gift_permision = app(ReferralGiftService::class)->resolveReferrerGiftPermission($referrer); app(ReferralGiftService::class)->tryGiveOnRegistration( $customer, $referrer, $gift_permision, false ); } } $companyName = $this->Config('name_fa'); $companyurl = self::publicSiteUrl(request()); $message ='حساب کاربری شما توسط کارشناس سیستم تایید شد '."\n". 'با رفتن به لینک زیر وارد حساب کاربری خود شوید'."\n". $companyurl."\n". 'با تشکر'.$this->Config('name_fa'); $this->Send($customer->mobile, $message); $referrer = $customer->referral; // if ($referrer) { // if (Customer::where('referral_to_id', $referrer->referral_id)->get()->count()<=$referrer->add_user_limit) { // $referrerWallet = Wallet::where('owner',$customer->referral->id)->first(); // $message = "سلام {$referrer->name} عزیز،\n\n{$gift_for_invite} گرم طلا بابت معرفی {$customer->name} به حساب شما واریز شد.\nموجودی فعلی: {$referrerWallet->gold} گرم.\n\nاطلاعات بیشتر: $companyurl\n\nبا احترام،\n$companyName"; // $this->Send($referrer->mobile, $message); // } // } return response()->json(true); } public function cardChecker(Request $request){ if (!app(ConfigService::class)->isJibitEnabled()) { throw new UnprocessableEntityHttpException('سرویس احراز هویت جیبیت غیرفعال است.'); } if (strlen($request->cart_number) != 16) { throw new UnprocessableEntityHttpException('شماره کارت اشتباه می‌باشد.'); } if (empty($request->national_code)) { throw new UnprocessableEntityHttpException('لطفا شماره ملی وارد کنید.'); } if(!empty($request->birth_date)){ $birth_date = Verta::instance(Carbon::parse($request->birth_date))->format('Ymd'); } $card_number = preg_replace('/\D/', '', $request->cart_number); $response = $this->jibit("cartMatching", $card_number, $request->national_code, $birth_date ?? null); if(isset($response['refresh'])){ unset($response['refresh']); } if(!empty($response)){ if(!empty($response['message'])){ throw new UnprocessableEntityHttpException($response['message']); }else{ return response()->json($response); } }else{ throw new UnprocessableEntityHttpException('ارتباط با سامانه قطع میباشد.'); } } }