/
itp_practice
/
itp_backend
Обзор
Документация
Войти
/
itp_practice
/
itp_backend
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
app/Services/SubscriptionService.php
261 строка
10 KB
vivanenko
run taps
29 май 2025, 21:05
29 май 2025, 21:05
b91be9d
Код
Авторство
О чём код?
<?php namespace App\Services; use App\Enum\Taps\TapStatusEnum; use App\Enums\TapProcessState; use App\Enums\TapStatus; use App\Helpers\PhoneSanitizeHelper; use App\Models\Order; use App\Models\Proxy; use App\Models\UserTariffSubscription; use App\Models\Tap; use App\Models\TapApp; use App\Enums\SubscriptionStatus; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; use Carbon\Carbon; use Illuminate\Support\Collection; use App\DTOs\Subscription\UserSubscriptionDTO; use App\Models\User; /** * Сервис для управления подписками пользователей * Реализует бизнес-логику создания и управления подписками */ class SubscriptionService { /** * Создает подписки пользователя на основе оплаченного заказа */ public function createSubscriptionsFromOrder(Order $order): array { Log::info('Creating user subscriptions from order', [ 'order_id' => $order->id, 'user_id' => $order->user_id, ]); $createdSubscriptions = []; $createdTaps = []; DB::beginTransaction(); try { // Получаем все элементы корзины для этого заказа $cartItems = $order->cartItems()->with('itemable.tapApps')->get(); Log::info(__METHOD__ . ' cart items count', ['count' => $cartItems->count()]); foreach ($cartItems as $cartItem) { // Проверяем, что это тариф if ($cartItem->itemable_type !== 'App\\Models\\Tariff') { Log::warning('Skipping non-tariff cart item', [ 'cart_item_id' => $cartItem->id, 'itemable_type' => $cartItem->itemable_type, ]); continue; } $tariff = $cartItem->itemable; if (!$tariff) { Log::warning('Tariff not found for cart item', [ 'cart_item_id' => $cartItem->id, ]); continue; } // Создаем подписки в количестве, указанном в корзине for ($i = 0; $i < $cartItem->quantity; $i++) { $subscription = $this->createSingleSubscription($order, $tariff); $createdSubscriptions[] = $subscription; // Создаем записи Tap для каждого TapApp в тарифе // $taps = $this->createTapsForSubscription($subscription, $tariff); // $createdTaps = array_merge($createdTaps, $taps); } } DB::commit(); Log::info('User subscriptions created successfully', [ 'order_id' => $order->id, 'subscriptions_created' => count($createdSubscriptions), 'taps_created' => count($createdTaps), ]); } catch (\Throwable $exception) { DB::rollBack(); Log::error('Failed to create subscriptions from order', ['error' => $exception->getMessage()]); } return [ 'subscriptions' => $createdSubscriptions, 'taps' => $createdTaps, ]; } /** * Создает одну подписку для пользователя */ private function createSingleSubscription(Order $order, $tariff): UserTariffSubscription { $startDate = Carbon::now(); $endDate = $tariff->duration_days > 0 ? $startDate->copy()->addDays($tariff->duration_days) : $startDate->copy(); // Если duration_days = 0, то дата окончания = дата начала $subscription = UserTariffSubscription::create([ 'user_id' => $order->user_id, 'tariff_id' => $tariff->id, 'status' => SubscriptionStatus::ACTIVE, 'start_date' => $startDate, 'end_date' => $endDate, 'order_id' => $order->id, ]); Log::info('Created subscription', [ 'subscription_id' => $subscription->id, 'user_id' => $order->user_id, 'tariff_id' => $tariff->id, 'start_date' => $startDate->toDateTimeString(), 'end_date' => $endDate->toDateTimeString(), ]); return $subscription; } /** * Создает записи Tap для подписки */ public function createTapsForSubscription( UserTariffSubscription $subscription, string $phone, int $proxyId ): Collection { Log::info('Creating taps for subscription', [ 'subscription_id' => $subscription->id, 'user_id' => $subscription->user_id, 'tariff_id' => $subscription->tariff_id, ]); /** @var TapApp[] $tapApps */ $tapApps = TapApp::query() ->select('tap_apps.*') ->join('tariff_tap_apps', 'tariff_tap_apps.tap_app_id', '=', 'tap_apps.id') ->where([ 'tap_apps.is_active' => true, 'tariff_tap_apps.tariff_id' => $subscription->tariff_id, ]) ->get(); Log::info('Creating taps with tap apps', [ 'tap_apps_count' => $tapApps->count(), ]); $taps = collect(); foreach ($tapApps as $tapApp) { $tap = Tap::create([ 'tap_app_id' => $tapApp->id, 'name' => $tapApp->getWorkName(), 'phone' => PhoneSanitizeHelper::sanitize($phone), 'proxy' => TapService::getProxyStringFromId($proxyId), 'status' => TapStatus::NEW, 'process_state' => TapProcessState::UNKNOWN, 'expired_at' => $subscription->end_date, 'balance' => 0, 'crm_user_id' => $subscription->user_id, ]); $subscription->taps()->attach($tap->id); $taps->push($tap); Log::info('Created tap', [ 'tap_id' => $tap->id, 'tap_app_name' => $tapApp->getWorkName(), ]); } return $taps; } /** * Получает активные подписки пользователя */ public function getUserActiveSubscriptions(int $userId): array { return UserTariffSubscription::where('user_id', $userId) ->where('status', SubscriptionStatus::ACTIVE) ->where('start_date', '<=', now()) ->where('end_date', '>=', now()) ->with(['tariff', 'taps.tapApp']) ->get() ->toArray(); } /** * Деактивирует подписку */ public function deactivateSubscription(int $subscriptionId, int $userId): bool { $subscription = UserTariffSubscription::where('id', $subscriptionId) ->where('user_id', $userId) ->first(); if (!$subscription) { throw new \InvalidArgumentException('Subscription not found'); } $subscription->update([ 'status' => SubscriptionStatus::CANCELLED, 'end_date' => now(), ]); // Деактивируем все связанные тапы $subscription->taps()->update([ 'is_active' => false, 'process_state' => 'stopped', ]); Log::info('Subscription deactivated', [ 'subscription_id' => $subscriptionId, 'user_id' => $userId, ]); return true; } /** * Проверяет и деактивирует истекшие подписки */ public function deactivateExpiredSubscriptions(): int { $expiredSubscriptions = UserTariffSubscription::where('status', SubscriptionStatus::ACTIVE) ->where('end_date', '<', now()) ->get(); $deactivatedCount = 0; foreach ($expiredSubscriptions as $subscription) { $this->deactivateSubscription($subscription->id, $subscription->user_id); $deactivatedCount++; } Log::info('Expired subscriptions deactivated', [ 'count' => $deactivatedCount, ]); return $deactivatedCount; } /** * Get all active subscriptions for a user with their details */ public function getUserSubscriptions(User $user): Collection { $subscriptions = UserTariffSubscription::query() ->with(['tariff', 'taps', 'telegramAccount']) ->where('user_id', $user->id) ->where('status', 'active') ->get(); return $subscriptions->map(function (UserTariffSubscription $subscription) { return UserSubscriptionDTO::fromModel($subscription); }); } }