user = User::where('email', 'demo@webmoney.com')->first(); if (!$this->user) { $this->error('Usuário demo@webmoney.com não encontrado!'); return Command::FAILURE; } $this->info("Populando dados para usuário DEMO (ID: {$this->user->id})..."); if ($this->option('fresh')) { $this->clearExistingData(); } DB::beginTransaction(); try { $this->createAccounts(); $this->createCategories(); $this->createTransactions(); // Recalcular saldos das contas $this->recalculateBalances(); DB::commit(); $this->newLine(); $this->info('✓ Dados DEMO populados com sucesso!'); $this->showSummary(); return Command::SUCCESS; } catch (\Exception $e) { DB::rollBack(); $this->error('Erro: ' . $e->getMessage()); $this->error($e->getTraceAsString()); return Command::FAILURE; } } private function clearExistingData(): void { $this->info('Limpando dados existentes...'); Transaction::where('user_id', $this->user->id)->delete(); // Subcategorias são Category com parent_id Category::where('user_id', $this->user->id)->whereNotNull('parent_id')->delete(); Category::where('user_id', $this->user->id)->whereNull('parent_id')->delete(); Account::where('user_id', $this->user->id)->delete(); } private function createAccounts(): void { $this->info('Criando contas...'); $accountsData = [ [ 'name' => 'Cuenta Corriente Principal', 'type' => 'checking', 'bank_name' => 'Santander', 'account_number' => 'ES12 3456 7890 1234', 'initial_balance' => 5000.00, 'currency' => 'EUR', 'color' => '#3B82F6', 'icon' => 'bi-bank', 'is_active' => true, 'include_in_total' => true, ], [ 'name' => 'Cuenta de Ahorro', 'type' => 'savings', 'bank_name' => 'BBVA', 'account_number' => 'ES98 7654 3210 9876', 'initial_balance' => 15000.00, 'currency' => 'EUR', 'color' => '#10B981', 'icon' => 'bi-piggy-bank', 'is_active' => true, 'include_in_total' => true, ], [ 'name' => 'Efectivo', 'type' => 'cash', 'bank_name' => null, 'account_number' => null, 'initial_balance' => 500.00, 'currency' => 'EUR', 'color' => '#F59E0B', 'icon' => 'bi-cash-stack', 'is_active' => true, 'include_in_total' => true, ], ]; foreach ($accountsData as $data) { $account = Account::create([ 'user_id' => $this->user->id, 'name' => $data['name'], 'type' => $data['type'], 'bank_name' => $data['bank_name'], 'account_number' => $data['account_number'], 'initial_balance' => $data['initial_balance'], 'current_balance' => $data['initial_balance'], 'currency' => $data['currency'], 'color' => $data['color'], 'icon' => $data['icon'], 'is_active' => $data['is_active'], 'include_in_total' => $data['include_in_total'], ]); $this->accounts[$data['type']] = $account; $this->info(" ✓ {$data['name']}"); } } private function createCategories(): void { $this->info('Criando categorias e subcategorias...'); $categoriesData = [ // DESPESAS (expense) [ 'name' => 'Vivienda', 'type' => 'debit', 'icon' => 'bi-house', 'color' => '#EF4444', 'subcategories' => ['Alquiler', 'Hipoteca', 'Comunidad', 'Seguro Hogar', 'Reparaciones', 'Muebles'], ], [ 'name' => 'Alimentación', 'type' => 'debit', 'icon' => 'bi-cart', 'color' => '#F97316', 'subcategories' => ['Supermercado', 'Restaurantes', 'Cafeterías', 'Delivery', 'Panadería'], ], [ 'name' => 'Transporte', 'type' => 'debit', 'icon' => 'bi-car-front', 'color' => '#8B5CF6', 'subcategories' => ['Combustible', 'Transporte Público', 'Taxi/Uber', 'Mantenimiento Coche', 'Parking', 'Seguro Coche'], ], [ 'name' => 'Servicios', 'type' => 'debit', 'icon' => 'bi-lightning', 'color' => '#EC4899', 'subcategories' => ['Electricidad', 'Gas', 'Agua', 'Internet', 'Teléfono', 'Streaming'], ], [ 'name' => 'Salud', 'type' => 'debit', 'icon' => 'bi-heart-pulse', 'color' => '#14B8A6', 'subcategories' => ['Médico', 'Farmacia', 'Dentista', 'Óptica', 'Gimnasio', 'Seguro Médico'], ], [ 'name' => 'Ocio', 'type' => 'debit', 'icon' => 'bi-controller', 'color' => '#6366F1', 'subcategories' => ['Cine', 'Conciertos', 'Viajes', 'Hobbies', 'Libros', 'Videojuegos'], ], [ 'name' => 'Ropa', 'type' => 'debit', 'icon' => 'bi-bag', 'color' => '#A855F7', 'subcategories' => ['Ropa', 'Calzado', 'Accesorios', 'Ropa Deportiva'], ], [ 'name' => 'Educación', 'type' => 'debit', 'icon' => 'bi-book', 'color' => '#0EA5E9', 'subcategories' => ['Cursos', 'Material Escolar', 'Idiomas', 'Certificaciones'], ], [ 'name' => 'Mascotas', 'type' => 'debit', 'icon' => 'bi-piggy-bank', 'color' => '#84CC16', 'subcategories' => ['Comida Mascota', 'Veterinario', 'Accesorios Mascota'], ], [ 'name' => 'Otros Gastos', 'type' => 'debit', 'icon' => 'bi-three-dots', 'color' => '#64748B', 'subcategories' => ['Regalos', 'Donaciones', 'Imprevistos', 'Varios'], ], // INGRESOS (income) [ 'name' => 'Salario', 'type' => 'credit', 'icon' => 'bi-briefcase', 'color' => '#22C55E', 'subcategories' => ['Nómina', 'Horas Extra', 'Bonus', 'Comisiones'], ], [ 'name' => 'Inversiones', 'type' => 'credit', 'icon' => 'bi-graph-up-arrow', 'color' => '#10B981', 'subcategories' => ['Dividendos', 'Intereses', 'Plusvalías', 'Alquileres'], ], [ 'name' => 'Freelance', 'type' => 'credit', 'icon' => 'bi-laptop', 'color' => '#06B6D4', 'subcategories' => ['Proyectos', 'Consultoría', 'Clases Particulares'], ], [ 'name' => 'Otros Ingresos', 'type' => 'credit', 'icon' => 'bi-plus-circle', 'color' => '#84CC16', 'subcategories' => ['Reembolsos', 'Ventas', 'Premios', 'Herencias'], ], ]; foreach ($categoriesData as $catData) { $category = Category::create([ 'user_id' => $this->user->id, 'name' => $catData['name'], 'type' => $catData['type'], 'icon' => $catData['icon'], 'color' => $catData['color'], 'is_active' => true, 'parent_id' => null, ]); $this->categories[$catData['name']] = $category; // Subcategorias são Category com parent_id foreach ($catData['subcategories'] as $subName) { $sub = Category::create([ 'user_id' => $this->user->id, 'parent_id' => $category->id, 'name' => $subName, 'type' => $catData['type'], 'icon' => $catData['icon'], 'color' => $catData['color'], 'is_active' => true, ]); $this->subcategories[$subName] = $sub; } $this->info(" ✓ {$catData['name']} ({$catData['type']}) - " . count($catData['subcategories']) . " subcategorias"); } } private function createTransactions(): void { $this->info('Criando transações de 2025-2026...'); $checkingAccount = $this->accounts['checking']; $savingsAccount = $this->accounts['savings']; $cashAccount = $this->accounts['cash']; $transactionCount = 0; $today = Carbon::today(); // Helper para determinar status baseado na data $getStatus = function(Carbon $date) use ($today) { return $date->isAfter($today) ? 'pending' : 'effective'; }; // Gerar transações de Janeiro 2025 a Março 2026 for ($i = 1; $i <= 15; $i++) { // 12 meses de 2025 + 3 de 2026 $year = $i <= 12 ? 2025 : 2026; $month = $i <= 12 ? $i : $i - 12; $daysInMonth = Carbon::create($year, $month)->daysInMonth; // RECEITAS FIXAS (mensais) // Salário - dia 28 ou último dia útil $salaryDay = min(28, $daysInMonth); $salaryDate = Carbon::create($year, $month, $salaryDay); $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Salario', 'subcategory' => 'Nómina', 'type' => 'credit', 'amount' => 3200.00, 'date' => $salaryDate, 'status' => $getStatus($salaryDate), 'description' => 'Salario mensual', ]); $transactionCount++; // DESPESAS FIXAS (mensais) // Aluguel - dia 1 $rentDate = Carbon::create($year, $month, 1); $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Vivienda', 'subcategory' => 'Alquiler', 'type' => 'debit', 'amount' => 850.00, 'date' => $rentDate, 'status' => $getStatus($rentDate), 'description' => 'Alquiler apartamento', ]); $transactionCount++; // Serviços - vários dias do mês $services = [ ['subcategory' => 'Electricidad', 'amount' => rand(45, 85), 'day' => 5], ['subcategory' => 'Gas', 'amount' => rand(25, 55), 'day' => 8], ['subcategory' => 'Agua', 'amount' => rand(20, 35), 'day' => 10], ['subcategory' => 'Internet', 'amount' => 49.99, 'day' => 15], ['subcategory' => 'Teléfono', 'amount' => 25.00, 'day' => 15], ['subcategory' => 'Streaming', 'amount' => 17.99, 'day' => 20], ]; foreach ($services as $service) { if ($service['day'] <= $daysInMonth) { $serviceDate = Carbon::create($year, $month, $service['day']); $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Servicios', 'subcategory' => $service['subcategory'], 'type' => 'debit', 'amount' => $service['amount'], 'date' => $serviceDate, 'status' => $getStatus($serviceDate), 'description' => $service['subcategory'], ]); $transactionCount++; } } // Supermercado - várias vezes por mês $supermarketDays = [3, 10, 17, 24]; foreach ($supermarketDays as $day) { if ($day <= $daysInMonth) { $marketDate = Carbon::create($year, $month, $day); $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Alimentación', 'subcategory' => 'Supermercado', 'type' => 'debit', 'amount' => rand(60, 120), 'date' => $marketDate, 'status' => $getStatus($marketDate), 'description' => 'Compra supermercado', ]); $transactionCount++; } } // Transporte - combustível e outros $fuelDate = Carbon::create($year, $month, rand(1, min(15, $daysInMonth))); $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Transporte', 'subcategory' => 'Combustible', 'type' => 'debit', 'amount' => rand(50, 80), 'date' => $fuelDate, 'status' => $getStatus($fuelDate), 'description' => 'Gasolina', ]); $transactionCount++; // Restaurantes - algumas vezes por mês $restaurantCount = rand(2, 4); for ($j = 0; $j < $restaurantCount; $j++) { $restaurantDate = Carbon::create($year, $month, rand(1, $daysInMonth)); $this->createTransaction([ 'account_id' => $cashAccount->id, 'category' => 'Alimentación', 'subcategory' => 'Restaurantes', 'type' => 'debit', 'amount' => rand(25, 60), 'date' => $restaurantDate, 'status' => $getStatus($restaurantDate), 'description' => 'Cena/Almuerzo fuera', ]); $transactionCount++; } // Café - várias vezes $coffeeCount = rand(5, 10); for ($j = 0; $j < $coffeeCount; $j++) { $coffeeDate = Carbon::create($year, $month, rand(1, $daysInMonth)); $this->createTransaction([ 'account_id' => $cashAccount->id, 'category' => 'Alimentación', 'subcategory' => 'Cafeterías', 'type' => 'debit', 'amount' => rand(3, 8), 'date' => $coffeeDate, 'status' => $getStatus($coffeeDate), 'description' => 'Café', ]); $transactionCount++; } // Retirada de cajero para efectivo (do banco para cash) $atmDate = Carbon::create($year, $month, rand(1, min(5, $daysInMonth))); $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Otros Gastos', 'subcategory' => 'Varios', 'type' => 'debit', 'amount' => 200.00, 'date' => $atmDate, 'status' => $getStatus($atmDate), 'description' => 'Retiro cajero automático', ]); $transactionCount++; $this->createTransaction([ 'account_id' => $cashAccount->id, 'category' => 'Otros Ingresos', 'subcategory' => 'Reembolsos', 'type' => 'credit', 'amount' => 200.00, 'date' => $atmDate, 'status' => $getStatus($atmDate), 'description' => 'Retiro cajero automático', ]); $transactionCount++; // Saúde - eventual if (rand(1, 3) == 1) { $healthDate = Carbon::create($year, $month, rand(1, $daysInMonth)); $healthSubs = ['Farmacia', 'Médico', 'Gimnasio']; $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Salud', 'subcategory' => $healthSubs[array_rand($healthSubs)], 'type' => 'debit', 'amount' => rand(15, 80), 'date' => $healthDate, 'status' => $getStatus($healthDate), 'description' => 'Gasto salud', ]); $transactionCount++; } // Ginásio - mensal $gymDate = Carbon::create($year, $month, 1); $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Salud', 'subcategory' => 'Gimnasio', 'type' => 'debit', 'amount' => 35.00, 'date' => $gymDate, 'status' => $getStatus($gymDate), 'description' => 'Cuota gimnasio', ]); $transactionCount++; // Lazer - algumas vezes if (rand(1, 2) == 1) { $leisureDate = Carbon::create($year, $month, rand(1, $daysInMonth)); $leisureSubs = ['Cine', 'Conciertos', 'Hobbies', 'Libros', 'Videojuegos']; $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Ocio', 'subcategory' => $leisureSubs[array_rand($leisureSubs)], 'type' => 'debit', 'amount' => rand(15, 60), 'date' => $leisureDate, 'status' => $getStatus($leisureDate), 'description' => 'Entretenimiento', ]); $transactionCount++; } // Roupa - eventual if (rand(1, 4) == 1) { $clothesDate = Carbon::create($year, $month, rand(1, $daysInMonth)); $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Ropa', 'subcategory' => 'Ropa', 'type' => 'debit', 'amount' => rand(30, 120), 'date' => $clothesDate, 'status' => $getStatus($clothesDate), 'description' => 'Compra ropa', ]); $transactionCount++; } // Freelance - eventual (2-3 vezes por trimestre) if ($month % 3 == 0 || rand(1, 5) == 1) { $freelanceDate = Carbon::create($year, $month, rand(10, min(25, $daysInMonth))); $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Freelance', 'subcategory' => 'Proyectos', 'type' => 'credit', 'amount' => rand(200, 800), 'date' => $freelanceDate, 'status' => $getStatus($freelanceDate), 'description' => 'Proyecto freelance', ]); $transactionCount++; } // Dividendos - trimestral if ($month % 3 == 0) { $dividendDate = Carbon::create($year, $month, 15); $this->createTransaction([ 'account_id' => $savingsAccount->id, 'category' => 'Inversiones', 'subcategory' => 'Dividendos', 'type' => 'credit', 'amount' => rand(50, 150), 'date' => $dividendDate, 'status' => $getStatus($dividendDate), 'description' => 'Dividendos trimestre', ]); $transactionCount++; } // Juros poupança - mensal $interestDate = Carbon::create($year, $month, $daysInMonth); $this->createTransaction([ 'account_id' => $savingsAccount->id, 'category' => 'Inversiones', 'subcategory' => 'Intereses', 'type' => 'credit', 'amount' => round(rand(15, 35) + (rand(0, 99) / 100), 2), 'date' => $interestDate, 'status' => $getStatus($interestDate), 'description' => 'Intereses cuenta ahorro', ]); $transactionCount++; // Transferência para poupança - mensal if (rand(1, 2) == 1) { $transferDate = Carbon::create($year, $month, rand(25, min(28, $daysInMonth))); $transferAmount = rand(200, 500); $this->createTransaction([ 'account_id' => $checkingAccount->id, 'category' => 'Otros Gastos', 'subcategory' => 'Varios', 'type' => 'debit', 'amount' => $transferAmount, 'date' => $transferDate, 'status' => $getStatus($transferDate), 'description' => 'Transferencia a cuenta ahorro', ]); $transactionCount++; $this->createTransaction([ 'account_id' => $savingsAccount->id, 'category' => 'Otros Ingresos', 'subcategory' => 'Reembolsos', 'type' => 'credit', 'amount' => $transferAmount, 'date' => $transferDate, 'status' => $getStatus($transferDate), 'description' => 'Transferencia desde cuenta corriente', ]); $transactionCount++; } $this->info(" ✓ Mes $month/$year procesado"); } $this->info(" Total: $transactionCount transacciones creadas"); } private function createTransaction(array $data): Transaction { $category = $this->categories[$data['category']] ?? null; // Subcategoria é usada diretamente como category_id (pois são Categories com parent_id) $subcategory = $this->subcategories[$data['subcategory']] ?? null; // Se tiver subcategoria, usa ela; senão usa a categoria pai $categoryId = $subcategory?->id ?? $category?->id; // Status vem do data ou default 'effective' $status = $data['status'] ?? 'effective'; // Para transações pendentes, não definir effective_date $effectiveDate = $status === 'pending' ? null : $data['date']; return Transaction::create([ 'user_id' => $this->user->id, 'account_id' => $data['account_id'], 'category_id' => $categoryId, 'type' => $data['type'], 'amount' => $status === 'pending' ? null : $data['amount'], 'planned_amount' => $data['amount'], 'planned_date' => $data['date'], 'effective_date' => $effectiveDate, 'description' => $data['description'], 'notes' => null, 'is_recurring' => false, 'status' => $status, ]); } private function recalculateBalances(): void { $this->info('Recalculando saldos das contas...'); foreach ($this->accounts as $account) { // Apenas transações efetivas afetam o saldo atual $income = Transaction::where('account_id', $account->id) ->where('type', 'credit') ->where('status', 'effective') ->sum('amount'); $expense = Transaction::where('account_id', $account->id) ->where('type', 'debit') ->where('status', 'effective') ->sum('amount'); $newBalance = $account->initial_balance + $income - $expense; $account->update(['current_balance' => $newBalance]); $this->info(" ✓ {$account->name}: €" . number_format($newBalance, 2)); } } private function showSummary(): void { $this->newLine(); $this->info('=== RESUMO ==='); $this->info('Contas: ' . count($this->accounts)); $this->info('Categorias: ' . count($this->categories)); $this->info('Subcategorias: ' . count($this->subcategories)); $this->info('Transações: ' . Transaction::where('user_id', $this->user->id)->count()); $this->newLine(); $this->info('Saldos finais:'); foreach ($this->accounts as $account) { $account->refresh(); $this->info(" {$account->name}: €" . number_format($account->current_balance, 2)); } } }