getBool('enable_digipay_installment', false); } public function publicConfig(): array { $cfg = app(ConfigService::class); return [ 'onboarding_url' => trim($cfg->getString('digipay_onboarding_url', '')), 'fee_shop_percent' => (float) $cfg->getString('digipay_fee_shop_percent', '8'), 'fee_gateway_percent' => (float) $cfg->getString('digipay_fee_gateway_percent', '5.7'), 'fee_extra_percent' => (float) $cfg->getString('digipay_fee_extra_percent', '2.3'), 'plan4_cap_toman' => (int) $cfg->getString('digipay_plan4_cap_toman', '30000000'), 'plan12_cap_toman' => (int) $cfg->getString('digipay_plan12_cap_toman', '200000000'), ]; } public function statusFor(int $customerId): array { $credit = DB::table('digipay_credits')->where('customer_id', $customerId)->first(); $config = $this->publicConfig(); return [ 'enabled' => true, 'status' => $credit->status ?? 'none', 'plan4_remaining_toman' => (int) floor(((int) ($credit->plan4_remaining_rial ?? 0)) / 10), 'plan12_remaining_toman' => (int) floor(((int) ($credit->plan12_remaining_rial ?? 0)) / 10), 'gram_price_rial' => $this->gramPriceRial(), 'config' => $config, ]; } public function markStarted(int $customerId): void { $config = $this->publicConfig(); if ($config['onboarding_url'] === '') { throw new UnprocessableEntityHttpException('لینک دیجی‌پی در تنظیمات ثبت نشده است'); } $existing = DB::table('digipay_credits')->where('customer_id', $customerId)->first(); if ($existing && $existing->status === 'active') { return; } if ($existing) { DB::table('digipay_credits')->where('id', $existing->id)->update([ 'status' => 'pending', 'updated_at' => now(), ]); return; } DB::table('digipay_credits')->insert([ 'customer_id' => $customerId, 'status' => 'pending', 'plan4_remaining_rial' => 0, 'plan12_remaining_rial' => 0, 'created_at' => now(), 'updated_at' => now(), ]); } public function setCredit(string $mobile, int $plan4Toman, int $plan12Toman): array { $customer = Customer::findActiveByMobile($mobile); if (! $customer) { throw new UnprocessableEntityHttpException('مشتری با این موبایل پیدا نشد'); } $row = [ 'status' => 'active', 'plan4_remaining_rial' => max(0, $plan4Toman) * 10, 'plan12_remaining_rial' => max(0, $plan12Toman) * 10, 'updated_at' => now(), ]; $existing = DB::table('digipay_credits')->where('customer_id', $customer->id)->first(); if ($existing) { DB::table('digipay_credits')->where('id', $existing->id)->update($row); } else { $row['customer_id'] = $customer->id; $row['created_at'] = now(); DB::table('digipay_credits')->insert($row); } return [ 'customer_id' => (int) $customer->id, 'name' => $customer->name, 'plan4_remaining_toman' => max(0, $plan4Toman), 'plan12_remaining_toman' => max(0, $plan12Toman), ]; } public function buy(int $customerId, int $plan, int $amountToman): array { if (! in_array($plan, [4, 12], true)) { throw new UnprocessableEntityHttpException('طرح اقساط نامعتبر است'); } if ($amountToman < 1000) { throw new UnprocessableEntityHttpException('مبلغ خرید را وارد کنید'); } $price = $this->gramPriceRial(); if ($price <= 0) { throw new UnprocessableEntityHttpException('قیمت لحظه‌ای در دسترس نیست'); } $config = $this->publicConfig(); $cap = $plan === 4 ? $config['plan4_cap_toman'] : $config['plan12_cap_toman']; if ($amountToman > $cap) { throw new UnprocessableEntityHttpException('مبلغ از سقف این طرح بیشتر است'); } $feePercent = $config['fee_shop_percent'] + $config['fee_gateway_percent'] + $config['fee_extra_percent']; $amountRial = $amountToman * 10; $chargeRial = (int) round($amountRial * (1 + ($feePercent / 100))); $feeRial = $chargeRial - $amountRial; $grams = round($amountRial / $price, 4); if ($grams <= 0) { throw new UnprocessableEntityHttpException('مقدار مس محاسبه‌شده نامعتبر است'); } $column = $plan === 4 ? 'plan4_remaining_rial' : 'plan12_remaining_rial'; return DB::transaction(function () use ($customerId, $plan, $amountRial, $feeRial, $grams, $price, $chargeRial, $column) { $credit = DB::table('digipay_credits')->where('customer_id', $customerId)->lockForUpdate()->first(); if (! $credit || $credit->status !== 'active') { throw new UnprocessableEntityHttpException('اعتبار اقساطی شما هنوز فعال نشده است'); } if ((int) $credit->{$column} < $chargeRial) { throw new UnprocessableEntityHttpException('مانده اعتبار این طرح کافی نیست'); } DB::table('digipay_credits')->where('id', $credit->id)->update([ $column => (int) $credit->{$column} - $chargeRial, 'updated_at' => now(), ]); $orderId = DB::table('digipay_orders')->insertGetId([ 'customer_id' => $customerId, 'plan' => $plan, 'amount_rial' => $amountRial, 'fee_rial' => $feeRial, 'grams' => $grams, 'gram_price_rial' => $price, 'status' => 'done', 'created_at' => now(), 'updated_at' => now(), ]); $this->creditMetal($customerId, $grams, (int) $orderId); return [ 'order_id' => (int) $orderId, 'grams' => $grams, 'plan' => $plan, 'charge_toman' => (int) floor($chargeRial / 10), ]; }); } public function recentOrders(int $limit = 50): array { return DB::table('digipay_orders as o') ->leftJoin('customers as c', 'c.id', '=', 'o.customer_id') ->orderByDesc('o.id') ->limit($limit) ->get([ 'o.id', 'o.customer_id', 'c.name', 'c.mobile', 'o.plan', 'o.amount_rial', 'o.fee_rial', 'o.grams', 'o.created_at', ]) ->map(function ($row) { return [ 'id' => (int) $row->id, 'customer_id' => (int) $row->customer_id, 'name' => $row->name, 'mobile' => $row->mobile, 'plan' => (int) $row->plan, 'amount_toman' => (int) floor(((int) $row->amount_rial) / 10), 'fee_toman' => (int) floor(((int) $row->fee_rial) / 10), 'grams' => (float) $row->grams, 'created_at' => $row->created_at, ]; }) ->all(); } private function gramPriceRial(): int { return (int) (Price::query()->orderByDesc('id')->value('price') ?? 0); } private function creditMetal(int $customerId, float $grams, int $orderId): void { $user = Customer::query()->find($customerId); if (! $user) { throw new UnprocessableEntityHttpException('مشتری پیدا نشد'); } $withdraw = Withdraw::create([ 'customer_id' => $user->id, 'gold' => $grams, 'note' => 'خرید اقساطی', 'sts' => 6, 'tracked_number' => $orderId, ]); $wallet = new WalletInterface($user->id, $user->type); new TransactionInterface($wallet, [ 'cash' => 0, 'gold' => $grams, 'expire_at' => now(), 'note' => 'خرید اقساطی', 'withdraw_id' => $withdraw->id, 'active' => true, ], 7, true, false); try { app(ShayeganSyncService::class)->recordWalletGold([ 'customer_id' => $user->id, 'value' => $grams, 'direction' => 1, 'withdraw_id' => $withdraw->id, 'note' => 'خرید اقساطی', ]); } catch (\Throwable $e) { report($e); } } }