22using MongoDB . Driver ;
33using MongoDB . Bson ;
44using Emprestimos . API . Models ;
5+ using Microsoft . AspNetCore . Authorization ;
56
67namespace Emprestimos . API . Controllers ;
78
9+ [ Authorize ]
810[ ApiController ]
911[ Route ( "api/[controller]" ) ]
1012public class EmprestimosController : ControllerBase
1113{
1214 private readonly IMongoCollection < Emprestimo > _emprestimos ;
1315 private readonly IMongoDatabase _db ;
1416
15- // Construtor único unificado
1617 public EmprestimosController ( IMongoDatabase database )
1718 {
1819 _db = database ;
1920 _emprestimos = database . GetCollection < Emprestimo > ( "emprestimos" ) ;
2021 }
2122
22- [ HttpGet ( "{id:int}/{nomeCobrador}" ) ]
23- public async Task < ActionResult < Emprestimo > > Get ( int id , string nomeCobrador )
24- {
23+ [ HttpGet ( "{id:int}" ) ]
24+ public async Task < ActionResult < Emprestimo > > Get ( int id )
25+ {
26+ var cobrador = User . Identity ? . Name ;
2527 var emprestimo = await _emprestimos
26- . Find ( x => x . Id == id && x . Cobrador == nomeCobrador )
28+ . Find ( x => x . Id == id && x . Cobrador == cobrador )
2729 . FirstOrDefaultAsync ( ) ;
28-
30+
2931 if ( emprestimo is null )
30- return NotFound ( new { mensagem = $ "Empréstimo { id } não encontrado para o cobrador { nomeCobrador } ." } ) ;
32+ return NotFound ( new { mensagem = $ "Empréstimo { id } não encontrado." } ) ;
3133
3234 return Ok ( emprestimo ) ;
3335 }
3436
35- [ HttpGet ( "carteira/{nomeCobrador} " ) ]
36- public async Task < ActionResult < IEnumerable < Emprestimo > > > GetCarteira ( string nomeCobrador )
37+ [ HttpGet ( "carteira" ) ]
38+ public async Task < ActionResult < IEnumerable < Emprestimo > > > GetCarteira ( )
3739 {
40+ var cobrador = User . Identity ? . Name ;
3841 var lista = await _emprestimos
39- . Find ( x => x . Cobrador == nomeCobrador && ! x . Pago )
42+ . Find ( x => x . Cobrador == cobrador && ! x . Pago )
4043 . SortBy ( x => x . DataVencimento )
4144 . ToListAsync ( ) ;
4245
4346 return Ok ( lista ) ;
4447 }
4548
46- [ HttpGet ( "relatorio-lucro/{nomeCobrador} " ) ]
47- public async Task < IActionResult > GetRelatorioLucro ( string nomeCobrador )
49+ [ HttpGet ( "relatorio-lucro" ) ]
50+ public async Task < IActionResult > GetRelatorioLucro ( )
4851 {
49- var emprestimos = await _emprestimos . Find ( x => x . Cobrador == nomeCobrador ) . ToListAsync ( ) ;
52+ var cobrador = User . Identity ? . Name ;
53+ var emprestimos = await _emprestimos . Find ( x => x . Cobrador == cobrador ) . ToListAsync ( ) ;
5054
5155 var totalInvestido = emprestimos . Sum ( x => x . Valor ) ;
5256 var totalAReceberGeral = emprestimos . Sum ( x => x . ValorFinal ) ;
@@ -61,7 +65,7 @@ public async Task<IActionResult> GetRelatorioLucro(string nomeCobrador)
6165 } ) ;
6266
6367 return Ok ( new {
64- Cobrador = nomeCobrador ,
68+ Cobrador = cobrador ,
6569 ResumoGeral = new {
6670 InvestimentoTotal = totalInvestido ,
6771 RecebimentoTotalGeral = totalAReceberGeral ,
@@ -71,169 +75,165 @@ public async Task<IActionResult> GetRelatorioLucro(string nomeCobrador)
7175 } ) ;
7276 }
7377
74- [ HttpPost ]
75- public async Task < IActionResult > Post ( Emprestimo novo )
76- {
77- var ultimoEmprestimo = await _emprestimos . Find ( _ => true ) . SortByDescending ( x => x . Id ) . FirstOrDefaultAsync ( ) ;
78- novo . Id = ( ultimoEmprestimo == null ) ? 1 : ultimoEmprestimo . Id + 1 ;
78+ [ HttpPost ]
79+ public async Task < IActionResult > Post ( Emprestimo novo )
80+ {
81+ novo . Cobrador = User . Identity ? . Name ?? novo . Cobrador ;
7982
80- if ( novo . TaxaJuros > 1 ) novo . TaxaJuros = novo . TaxaJuros / 100 ;
81- if ( novo . TaxaJuros == 0 ) novo . TaxaJuros = 0.30m ;
83+ var ultimoEmprestimo = await _emprestimos . Find ( _ => true ) . SortByDescending ( x => x . Id ) . FirstOrDefaultAsync ( ) ;
84+ novo . Id = ( ultimoEmprestimo == null ) ? 1 : ultimoEmprestimo . Id + 1 ;
8285
83- if ( novo . NumeroParcelas <= 0 ) novo . NumeroParcelas = 1 ;
86+ if ( novo . TaxaJuros > 1 ) novo . TaxaJuros = novo . TaxaJuros / 100 ;
87+ if ( novo . TaxaJuros == 0 ) novo . TaxaJuros = 0.30m ;
8488
85- // Juros simples: ValorFinal = Valor * (1 + TaxaJuros)
86- novo . ValorFinal = novo . Valor * ( 1 + novo . TaxaJuros ) ;
87- novo . ValorParcela = Math . Round ( novo . ValorFinal / novo . NumeroParcelas , 2 ) ;
89+ if ( novo . NumeroParcelas <= 0 ) novo . NumeroParcelas = 1 ;
8890
89- novo . DataEmprestimo = DateTime . UtcNow ;
91+ novo . ValorFinal = novo . Valor * ( 1 + novo . TaxaJuros ) ;
92+ novo . ValorParcela = Math . Round ( novo . ValorFinal / novo . NumeroParcelas , 2 ) ;
93+ novo . DataEmprestimo = DateTime . UtcNow ;
9094
91- // Se não informou primeiro vencimento, assume 30 dias
92- if ( novo . DataVencimento == default )
93- novo . DataVencimento = DateTime . UtcNow . AddDays ( 30 ) ;
95+ if ( novo . DataVencimento == default )
96+ novo . DataVencimento = DateTime . UtcNow . AddDays ( 30 ) ;
9497
95- // Gera as parcelas a cada 30 dias a partir do primeiro vencimento
96- novo . Parcelas = new List < Parcela > ( ) ;
97- for ( int i = 0 ; i < novo . NumeroParcelas ; i ++ )
98- {
99- novo . Parcelas . Add ( new Parcela
98+ novo . Parcelas = new List < Parcela > ( ) ;
99+ for ( int i = 0 ; i < novo . NumeroParcelas ; i ++ )
100100 {
101- Numero = i + 1 ,
102- Valor = novo . ValorParcela ,
103- DataVencimento = novo . DataVencimento . AddDays ( 30 * i ) ,
104- Pago = false
105- } ) ;
106- }
101+ novo . Parcelas . Add ( new Parcela
102+ {
103+ Numero = i + 1 ,
104+ Valor = novo . ValorParcela ,
105+ DataVencimento = novo . DataVencimento . AddDays ( 30 * i ) ,
106+ Pago = false
107+ } ) ;
108+ }
107109
108- novo . Pago = false ;
110+ novo . Pago = false ;
109111
110- await _emprestimos . InsertOneAsync ( novo ) ;
112+ await _emprestimos . InsertOneAsync ( novo ) ;
111113
112- // NOTIFICAÇÃO ÚNICA DE NOVO EMPRÉSTIMO
113- var colNotificacoes = _db . GetCollection < Notificacao > ( "notificacoes" ) ;
114- var ultima = await colNotificacoes . Find ( _ => true ) . SortByDescending ( x => x . Id ) . FirstOrDefaultAsync ( ) ;
114+ var colNotificacoes = _db . GetCollection < Notificacao > ( "notificacoes" ) ;
115+ var ultima = await colNotificacoes . Find ( _ => true ) . SortByDescending ( x => x . Id ) . FirstOrDefaultAsync ( ) ;
115116
116- var mensagem = novo . NumeroParcelas == 1
117- ? $ "Novo empréstimo criado para { novo . Cliente } — vence em { novo . DataVencimento : dd/MM/yyyy} "
118- : $ "Novo empréstimo criado para { novo . Cliente } — { novo . NumeroParcelas } x de { novo . ValorParcela : C} , primeiro vencimento em { novo . DataVencimento : dd/MM/yyyy} ";
117+ var mensagem = novo . NumeroParcelas == 1
118+ ? $ "Novo empréstimo criado para { novo . Cliente } — vence em { novo . DataVencimento : dd/MM/yyyy} "
119+ : $ "Novo empréstimo criado para { novo . Cliente } — { novo . NumeroParcelas } x de { novo . ValorParcela : C} , primeiro vencimento em { novo . DataVencimento : dd/MM/yyyy} ";
119120
120- var novaNotif = new Notificacao
121- {
122- Id = ( ultima == null ) ? 1 : ultima . Id + 1 ,
123- ClienteId = novo . ClienteId ,
124- ClienteNome = novo . Cliente ,
125- Cobrador = novo . Cobrador ,
126- Valor = novo . ValorFinal ,
127- DataVencimento = novo . DataVencimento ,
128- Tipo = "Cobrança" ,
129- DataCriacao = DateTime . UtcNow ,
130- Lida = false ,
131- Mensagem = mensagem
132- } ;
133-
134- await colNotificacoes . InsertOneAsync ( novaNotif ) ;
121+ var novaNotif = new Notificacao
122+ {
123+ Id = ( ultima == null ) ? 1 : ultima . Id + 1 ,
124+ ClienteId = novo . ClienteId ,
125+ ClienteNome = novo . Cliente ,
126+ Cobrador = novo . Cobrador ,
127+ Valor = novo . ValorFinal ,
128+ DataVencimento = novo . DataVencimento ,
129+ Tipo = "Cobrança" ,
130+ DataCriacao = DateTime . UtcNow ,
131+ Lida = false ,
132+ Mensagem = mensagem
133+ } ;
134+
135+ await colNotificacoes . InsertOneAsync ( novaNotif ) ;
135136 await EnviarPushAsync ( novo . Cobrador , "Novo Empréstimo" , mensagem ) ;
136137
137- return CreatedAtAction ( nameof ( Get ) , new { id = novo . Id , nomeCobrador = novo . Cobrador } , novo ) ;
138- }
139- [ HttpPatch ( "{id:int}/pagar/{nomeCobrador}" ) ]
140- public async Task < IActionResult > MarcarComoPago ( int id , string nomeCobrador )
141- {
142- var emprestimo = await _emprestimos
143- . Find ( x => x . Id == id && x . Cobrador == nomeCobrador )
144- . FirstOrDefaultAsync ( ) ;
138+ return CreatedAtAction ( nameof ( Get ) , new { id = novo . Id } , novo ) ;
139+ }
145140
146- if ( emprestimo is null )
147- return NotFound ( new { mensagem = "Empréstimo não encontrado." } ) ;
141+ [ HttpPatch ( "{id:int}/pagar" ) ]
142+ public async Task < IActionResult > MarcarComoPago ( int id )
143+ {
144+ var cobrador = User . Identity ? . Name ;
148145
149- // Encontra a próxima parcela pendente
150- var parcelaPendente = emprestimo . Parcelas
151- . Where ( p => ! p . Pago )
152- . OrderBy ( p => p . Numero )
153- . FirstOrDefault ( ) ;
146+ var emprestimo = await _emprestimos
147+ . Find ( x => x . Id == id && x . Cobrador == cobrador )
148+ . FirstOrDefaultAsync ( ) ;
154149
155- if ( parcelaPendente != null )
156- {
157- parcelaPendente . Pago = true ;
158- parcelaPendente . DataPagamento = DateTime . UtcNow ;
159- }
150+ if ( emprestimo is null )
151+ return NotFound ( new { mensagem = "Empréstimo não encontrado." } ) ;
160152
161- // Verifica se todas as parcelas foram pagas
162- bool todasPagas = emprestimo . Parcelas . All ( p => p . Pago ) ;
153+ var parcelaPendente = emprestimo . Parcelas
154+ . Where ( p => ! p . Pago )
155+ . OrderBy ( p => p . Numero )
156+ . FirstOrDefault ( ) ;
163157
164- var filter = Builders < Emprestimo > . Filter . And (
165- Builders < Emprestimo > . Filter . Eq ( x => x . Id , id ) ,
166- Builders < Emprestimo > . Filter . Eq ( x => x . Cobrador , nomeCobrador )
167- ) ;
158+ if ( parcelaPendente != null )
159+ {
160+ parcelaPendente . Pago = true ;
161+ parcelaPendente . DataPagamento = DateTime . UtcNow ;
162+ }
168163
169- var update = Builders < Emprestimo > . Update
170- . Set ( x => x . Parcelas , emprestimo . Parcelas )
171- . Set ( x => x . Pago , todasPagas )
172- . Set ( x => x . Status , todasPagas ? StatusPagamento . Pago : StatusPagamento . Pendente )
173- . Set ( x => x . DataPagamento , todasPagas ? DateTime . UtcNow : ( DateTime ? ) null ) ;
164+ bool todasPagas = emprestimo . Parcelas . All ( p => p . Pago ) ;
174165
175- var emprestimoAtualizado = await _emprestimos . FindOneAndUpdateAsync (
176- filter ,
177- update ,
178- new FindOneAndUpdateOptions < Emprestimo > { ReturnDocument = ReturnDocument . After }
179- ) ;
166+ var filter = Builders < Emprestimo > . Filter . And (
167+ Builders < Emprestimo > . Filter . Eq ( x => x . Id , id ) ,
168+ Builders < Emprestimo > . Filter . Eq ( x => x . Cobrador , cobrador )
169+ ) ;
180170
181- if ( emprestimoAtualizado is null )
182- return NotFound ( new { mensagem = "Empréstimo não encontrado." } ) ;
171+ var update = Builders < Emprestimo > . Update
172+ . Set ( x => x . Parcelas , emprestimo . Parcelas )
173+ . Set ( x => x . Pago , todasPagas )
174+ . Set ( x => x . Status , todasPagas ? StatusPagamento . Pago : StatusPagamento . Pendente )
175+ . Set ( x => x . DataPagamento , todasPagas ? DateTime . UtcNow : ( DateTime ? ) null ) ;
183176
184- // NOTIFICAÇÃO DE PAGAMENTO
185- var colNotificacoes = _db . GetCollection < Notificacao > ( "notificacoes" ) ;
186- var ultima = await colNotificacoes . Find ( _ => true ) . SortByDescending ( x => x . Id ) . FirstOrDefaultAsync ( ) ;
177+ var emprestimoAtualizado = await _emprestimos . FindOneAndUpdateAsync (
178+ filter ,
179+ update ,
180+ new FindOneAndUpdateOptions < Emprestimo > { ReturnDocument = ReturnDocument . After }
181+ ) ;
187182
188- var parcelasPagas = emprestimoAtualizado . Parcelas . Count ( p => p . Pago ) ;
189- var totalParcelas = emprestimoAtualizado . NumeroParcelas ;
183+ if ( emprestimoAtualizado is null )
184+ return NotFound ( new { mensagem = "Empréstimo não encontrado." } ) ;
190185
191- var mensagem = todasPagas
192- ? $ "💰 RECEBIDO: { emprestimoAtualizado . Cliente } quitou o empréstimo!"
193- : $ "💰 RECEBIDO: { emprestimoAtualizado . Cliente } pagou parcela { parcelasPagas } /{ totalParcelas } — { emprestimoAtualizado . ValorParcela : C} ";
186+ var colNotificacoes = _db . GetCollection < Notificacao > ( "notificacoes" ) ;
187+ var ultima = await colNotificacoes . Find ( _ => true ) . SortByDescending ( x => x . Id ) . FirstOrDefaultAsync ( ) ;
194188
195- var notificacaoPagamento = new Notificacao
196- {
197- Id = ( ultima == null ) ? 1 : ultima . Id + 1 ,
198- ClienteId = emprestimoAtualizado . ClienteId ,
199- ClienteNome = emprestimoAtualizado . Cliente ,
200- Cobrador = nomeCobrador ,
201- Valor = emprestimoAtualizado . ValorParcela ,
202- Tipo = "Pagamento" ,
203- Data = DateTime . UtcNow ,
204- Lida = false ,
205- Mensagem = mensagem ,
206- NumeroParcela = parcelasPagas ,
207- TotalParcelas = totalParcelas
208- } ;
209-
210-
211- await colNotificacoes . InsertOneAsync ( notificacaoPagamento ) ;
212- await EnviarPushAsync ( nomeCobrador , "Pagamento Recebido" , mensagem ) ;
189+ var parcelasPagas = emprestimoAtualizado . Parcelas . Count ( p => p . Pago ) ;
190+ var totalParcelas = emprestimoAtualizado . NumeroParcelas ;
213191
214- var parcelasPendentes = emprestimoAtualizado . Parcelas . Count ( p => ! p . Pago ) ;
215- var saldoPendente = parcelasPendentes * emprestimoAtualizado . ValorParcela ;
192+ var mensagem = todasPagas
193+ ? $ "💰 RECEBIDO: { emprestimoAtualizado . Cliente } quitou o empréstimo!"
194+ : $ "💰 RECEBIDO: { emprestimoAtualizado . Cliente } pagou parcela { parcelasPagas } /{ totalParcelas } — { emprestimoAtualizado . ValorParcela : C} ";
216195
217- return Ok ( new
218- {
219- mensagem = todasPagas ? "Empréstimo quitado!" : $ "Parcela { parcelasPagas } /{ totalParcelas } registrada.",
220- parcelasPagas ,
221- parcelasPendentes ,
222- saldoPendente ,
223- dados = emprestimoAtualizado
224- } ) ;
225- }
196+ var notificacaoPagamento = new Notificacao
197+ {
198+ Id = ( ultima == null ) ? 1 : ultima . Id + 1 ,
199+ ClienteId = emprestimoAtualizado . ClienteId ,
200+ ClienteNome = emprestimoAtualizado . Cliente ,
201+ Cobrador = cobrador ,
202+ Valor = emprestimoAtualizado . ValorParcela ,
203+ Tipo = "Pagamento" ,
204+ Data = DateTime . UtcNow ,
205+ Lida = false ,
206+ Mensagem = mensagem ,
207+ NumeroParcela = parcelasPagas ,
208+ TotalParcelas = totalParcelas
209+ } ;
210+
211+ await colNotificacoes . InsertOneAsync ( notificacaoPagamento ) ;
212+ await EnviarPushAsync ( cobrador , "Pagamento Recebido" , mensagem ) ;
213+
214+ var parcelasPendentes = emprestimoAtualizado . Parcelas . Count ( p => ! p . Pago ) ;
215+ var saldoPendente = parcelasPendentes * emprestimoAtualizado . ValorParcela ;
226216
217+ return Ok ( new
218+ {
219+ mensagem = todasPagas ? "Empréstimo quitado!" : $ "Parcela { parcelasPagas } /{ totalParcelas } registrada.",
220+ parcelasPagas ,
221+ parcelasPendentes ,
222+ saldoPendente ,
223+ dados = emprestimoAtualizado
224+ } ) ;
225+ }
227226
228- [ HttpDelete ( "{id:int}/{nomeCobrador} " ) ]
229- public async Task < IActionResult > Delete ( int id , string nomeCobrador )
227+ [ HttpDelete ( "{id:int}" ) ]
228+ public async Task < IActionResult > Delete ( int id )
230229 {
231- var result = await _emprestimos . DeleteOneAsync ( x => x . Id == id && x . Cobrador == nomeCobrador ) ;
230+ var cobrador = User . Identity ? . Name ;
231+ var result = await _emprestimos . DeleteOneAsync ( x => x . Id == id && x . Cobrador == cobrador ) ;
232232 if ( result . DeletedCount == 0 ) return NotFound ( ) ;
233233 return NoContent ( ) ;
234234 }
235235
236- private async Task EnviarPushAsync ( string cobrador , string titulo , string mensagem )
236+ private async Task EnviarPushAsync ( string ? cobrador , string titulo , string mensagem )
237237 {
238238 try
239239 {
@@ -293,7 +293,7 @@ public async Task<IActionResult> VerificarAtrasos()
293293
294294 var mensagem = emp . NumeroParcelas == 1
295295 ? $ "⚠️ ATRASO: { emp . Cliente } está { diasAtraso } dia(s) em atraso — { emp . ValorFinal : C} "
296- : $ "⚠️ ATRASO: { emp . Cliente } — parcela { parcela . Numero } /{ emp . NumeroParcelas } ({ parcela . Valor : C} ) está { diasAtraso } dia(s) em atraso";
296+ : $ "⚠️ ATRASO: { emp . Cliente } — parcela { emp . NumeroParcelas } /{ emp . NumeroParcelas } ({ parcela . Valor : C} ) está { diasAtraso } dia(s) em atraso";
297297
298298 var ultima = await colNotificacoes . Find ( _ => true ) . SortByDescending ( x => x . Id ) . FirstOrDefaultAsync ( ) ;
299299
@@ -335,5 +335,4 @@ public async Task<IActionResult> VerificarAtrasos()
335335
336336 return Ok ( new { mensagem = $ "{ count } notificações de atraso enviadas." } ) ;
337337 }
338-
339- }
338+ }
0 commit comments