- Removido README.md padrão do Laravel (backend) - Removidos scripts de deploy (não mais necessários) - Atualizado copilot-instructions.md para novo fluxo - Adicionada documentação de auditoria do servidor - Sincronizado código de produção com repositório Novo workflow: - Trabalhamos diretamente em /root/webmoney (symlink para /var/www/webmoney) - Mudanças PHP são instantâneas - Mudanças React requerem 'npm run build' - Commit após validação funcional
262 lines
8.1 KiB
PHP
Executable File
262 lines
8.1 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Account;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class AccountController extends Controller
|
|
{
|
|
/**
|
|
* Listar todas as contas do usuário
|
|
*/
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
$query = Account::where('user_id', Auth::id());
|
|
|
|
// Filtros opcionais
|
|
if ($request->has('type')) {
|
|
$query->where('type', $request->type);
|
|
}
|
|
|
|
if ($request->has('is_active')) {
|
|
$query->where('is_active', $request->boolean('is_active'));
|
|
}
|
|
|
|
$accounts = $query->orderBy('name')->get();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => $accounts,
|
|
'types' => Account::TYPES,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Criar nova conta
|
|
*/
|
|
public function store(Request $request): JsonResponse
|
|
{
|
|
$validated = $request->validate([
|
|
'name' => 'required|string|max:100',
|
|
'type' => ['required', Rule::in(array_keys(Account::TYPES))],
|
|
'bank_name' => 'nullable|string|max:100',
|
|
'account_number' => 'nullable|string|max:50',
|
|
'initial_balance' => 'nullable|numeric',
|
|
'credit_limit' => 'nullable|numeric',
|
|
'currency' => 'nullable|string|size:3',
|
|
'color' => 'nullable|string|max:7',
|
|
'icon' => 'nullable|string|max:50',
|
|
'description' => 'nullable|string',
|
|
'is_active' => 'nullable|boolean',
|
|
'include_in_total' => 'nullable|boolean',
|
|
]);
|
|
|
|
$validated['user_id'] = Auth::id();
|
|
$validated['current_balance'] = $validated['initial_balance'] ?? 0;
|
|
|
|
$account = Account::create($validated);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Conta criada com sucesso',
|
|
'data' => $account,
|
|
], 201);
|
|
}
|
|
|
|
/**
|
|
* Exibir uma conta específica
|
|
*/
|
|
public function show(int $id): JsonResponse
|
|
{
|
|
$account = Account::where('user_id', Auth::id())->findOrFail($id);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => $account,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Atualizar uma conta
|
|
*/
|
|
public function update(Request $request, int $id): JsonResponse
|
|
{
|
|
$account = Account::where('user_id', Auth::id())->findOrFail($id);
|
|
|
|
$validated = $request->validate([
|
|
'name' => 'sometimes|required|string|max:100',
|
|
'type' => ['sometimes', 'required', Rule::in(array_keys(Account::TYPES))],
|
|
'bank_name' => 'nullable|string|max:100',
|
|
'account_number' => 'nullable|string|max:50',
|
|
'initial_balance' => 'nullable|numeric',
|
|
'credit_limit' => 'nullable|numeric',
|
|
'currency' => 'nullable|string|size:3',
|
|
'color' => 'nullable|string|max:7',
|
|
'icon' => 'nullable|string|max:50',
|
|
'description' => 'nullable|string',
|
|
'is_active' => 'nullable|boolean',
|
|
'include_in_total' => 'nullable|boolean',
|
|
]);
|
|
|
|
$account->update($validated);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Conta atualizada com sucesso',
|
|
'data' => $account->fresh(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Deletar uma conta (soft delete)
|
|
*/
|
|
public function destroy(int $id): JsonResponse
|
|
{
|
|
$account = Account::where('user_id', Auth::id())->findOrFail($id);
|
|
$account->delete();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Conta excluída com sucesso',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Retorna o saldo total de todas as contas
|
|
*/
|
|
public function totalBalance(): JsonResponse
|
|
{
|
|
$accounts = Account::where('user_id', Auth::id())
|
|
->active()
|
|
->includeInTotal()
|
|
->get();
|
|
|
|
$total = 0;
|
|
foreach ($accounts as $account) {
|
|
// Para passivos e cartões de crédito, o saldo é negativo
|
|
if ($account->isCreditAccount()) {
|
|
$total += (float) $account->current_balance; // já é negativo
|
|
} else {
|
|
$total += (float) $account->current_balance;
|
|
}
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => [
|
|
'total_balance' => $total,
|
|
'accounts_count' => $accounts->count(),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Recalcular saldos de todas as contas do usuário
|
|
*/
|
|
public function recalculateBalances(): JsonResponse
|
|
{
|
|
$accounts = Account::where('user_id', Auth::id())->get();
|
|
|
|
$results = [];
|
|
foreach ($accounts as $account) {
|
|
$oldBalance = (float) $account->current_balance;
|
|
$newBalance = $account->recalculateBalance();
|
|
|
|
$results[] = [
|
|
'id' => $account->id,
|
|
'name' => $account->name,
|
|
'old_balance' => $oldBalance,
|
|
'new_balance' => $newBalance,
|
|
'difference' => $newBalance - $oldBalance,
|
|
];
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Saldos recalculados com sucesso',
|
|
'data' => $results,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Recalcular saldo de uma conta específica
|
|
*/
|
|
public function recalculateBalance(int $id): JsonResponse
|
|
{
|
|
$account = Account::where('user_id', Auth::id())->findOrFail($id);
|
|
|
|
$oldBalance = (float) $account->current_balance;
|
|
$newBalance = $account->recalculateBalance();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Saldo recalculado com sucesso',
|
|
'data' => [
|
|
'id' => $account->id,
|
|
'name' => $account->name,
|
|
'old_balance' => $oldBalance,
|
|
'new_balance' => $newBalance,
|
|
'difference' => $newBalance - $oldBalance,
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Ajustar saldo de uma conta definindo o saldo real atual
|
|
* Calcula e atualiza o initial_balance para que: initial_balance + créditos - débitos = saldo_desejado
|
|
*/
|
|
public function adjustBalance(Request $request, int $id): JsonResponse
|
|
{
|
|
$validated = $request->validate([
|
|
'target_balance' => 'required|numeric',
|
|
]);
|
|
|
|
$account = Account::where('user_id', Auth::id())->findOrFail($id);
|
|
|
|
$targetBalance = (float) $validated['target_balance'];
|
|
$oldInitialBalance = (float) $account->initial_balance;
|
|
$oldCurrentBalance = (float) $account->current_balance;
|
|
|
|
// Calcular soma de transações
|
|
$credits = (float) $account->transactions()
|
|
->where('type', 'credit')
|
|
->where('status', 'completed')
|
|
->sum('amount');
|
|
|
|
$debits = (float) $account->transactions()
|
|
->where('type', 'debit')
|
|
->where('status', 'completed')
|
|
->sum('amount');
|
|
|
|
// Calcular novo initial_balance: target = initial + credits - debits
|
|
// initial = target - credits + debits
|
|
$newInitialBalance = $targetBalance - $credits + $debits;
|
|
|
|
// Atualizar conta
|
|
$account->update([
|
|
'initial_balance' => $newInitialBalance,
|
|
'current_balance' => $targetBalance,
|
|
]);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Saldo ajustado com sucesso',
|
|
'data' => [
|
|
'id' => $account->id,
|
|
'name' => $account->name,
|
|
'old_initial_balance' => $oldInitialBalance,
|
|
'new_initial_balance' => $newInitialBalance,
|
|
'old_current_balance' => $oldCurrentBalance,
|
|
'new_current_balance' => $targetBalance,
|
|
'credits_sum' => $credits,
|
|
'debits_sum' => $debits,
|
|
],
|
|
]);
|
|
}
|
|
}
|