Arthur-Attili commited on
Commit
543325c
·
verified ·
1 Parent(s): 41bb393

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -83
app.py CHANGED
@@ -92,18 +92,43 @@ def buscar_combinacoes_otimizado(credito_desejado, entrada_desejada, parcela_des
92
 
93
  print(f"🔍 Total de administradoras no filtro: {len(grupos_filtrados)}")
94
 
95
- # TOLERÂNCIAS - Ajustadas para valores altos
96
- # Para valores muito altos, aumentamos as tolerâncias
97
- if credito_desejado > 5000000: # Para valores acima de 5 milhões
98
- tolerancia_credito = 0.15 # 15%
99
- tolerancia_entrada = 0.15 # 15%
100
- tolerancia_parcela = 0.40 # 40%
101
- max_cotas_combinacao = 6 # Até 6 cotas por combinação
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  else:
103
- tolerancia_credito = 0.10 # 10%
104
- tolerancia_entrada = 0.10 # 10%
105
- tolerancia_parcela = 0.30 # 30%
106
- max_cotas_combinacao = 4 # Até 4 cotas por combinação
107
 
108
  # Define faixas de tolerância
109
  credito_min = credito_desejado * (1 - tolerancia_credito)
@@ -120,29 +145,32 @@ def buscar_combinacoes_otimizado(credito_desejado, entrada_desejada, parcela_des
120
  print(f"🔧 Faixas aceitáveis: Parcela: R$ {parcela_min:,.2f} - R$ {parcela_max:,.2f}")
121
  print(f"🔧 Máximo de cotas por combinação: {max_cotas_combinacao}")
122
 
 
123
  resultados = []
124
- total_combinacoes_testadas = 0
125
 
126
- # Para cada administradora, busca combinações
127
- for adm, cotas in grupos_filtrados.items():
128
- print(f"🔍 Analisando administradora: {adm} ({len(cotas)} cotas)")
129
-
130
- # Para valores altos, NÃO filtramos cotas individuais primeiro
131
- # Isso permite que cotas menores sejam combinadas para atingir valores altos
132
- cotas_para_combinar = cotas
133
 
134
- # Gera combinações
135
- for r in range(1, min(max_cotas_combinacao + 1, len(cotas_para_combinar) + 1)):
136
- # Limita o número de combinações testadas por administradora
137
- max_combinacoes_por_adm = 200 if credito_desejado > 5000000 else 100
138
- combinacoes_geradas = 0
 
 
 
 
 
139
 
140
- for combinacao in itertools.combinations(cotas_para_combinar, r):
141
- if combinacoes_geradas >= max_combinacoes_por_adm:
142
  break
143
 
144
- total_combinacoes_testadas += 1
145
- combinacoes_geradas += 1
146
 
147
  total_credito = sum(c['valor_credito'] for c in combinacao)
148
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
@@ -160,30 +188,28 @@ def buscar_combinacoes_otimizado(credito_desejado, entrada_desejada, parcela_des
160
 
161
  resultados.append((adm, combinacao, diferenca))
162
 
163
- # Para se encontrou combinações suficientes
164
- if len(resultados) >= max_combinacoes * 3:
165
  break
166
 
167
- if len(resultados) >= max_combinacoes * 3:
168
  break
169
 
170
- if len(resultados) >= max_combinacoes * 3:
171
  break
172
 
173
- print(f"🔍 Total de combinações testadas: {total_combinacoes_testadas}")
174
  print(f"🔍 Combinações válidas encontradas: {len(resultados)}")
175
 
 
176
  if not resultados:
177
- # Tenta uma busca mais ampla se não encontrou resultados
178
  print("🔍 Nenhuma combinação encontrada. Tentando busca ampla...")
179
  return buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejada, administradoras, max_combinacoes)
180
 
181
- # Ordena pela diferença e pega as melhores
182
  resultados.sort(key=lambda x: x[2])
183
  return formatar_resultados(resultados[:max_combinacoes])
184
 
185
  def buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None, max_combinacoes=10):
186
- """Busca combinações com tolerâncias mais amplas para valores altos."""
187
  global grupos_imovel
188
 
189
  # Filtra administradoras se especificado
@@ -192,17 +218,18 @@ def buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejad
192
  else:
193
  grupos_filtrados = grupos_imovel
194
 
195
- # Tolerâncias mais amplas para valores altos
196
- if credito_desejado > 5000000:
197
- tolerancia_credito = 0.25 # 25%
198
- tolerancia_entrada = 0.25 # 25%
199
- tolerancia_parcela = 0.60 # 60%
200
- max_cotas_combinacao = 8 # Até 8 cotas por combinação
 
201
  else:
202
- tolerancia_credito = 0.20 # 20%
203
- tolerancia_entrada = 0.20 # 20%
204
- tolerancia_parcela = 0.50 # 50%
205
- max_cotas_combinacao = 6 # Até 6 cotas por combinação
206
 
207
  credito_min = credito_desejado * (1 - tolerancia_credito)
208
  credito_max = credito_desejado * (1 + tolerancia_credito)
@@ -215,22 +242,27 @@ def buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejad
215
  print(f"🔍 BUSCA AMPLA: Máximo de cotas por combinação: {max_cotas_combinacao}")
216
 
217
  resultados = []
218
- total_combinacoes_testadas = 0
219
 
220
- for adm, cotas in grupos_filtrados.items():
221
- print(f"🔍 BUSCA AMPLA - Analisando administradora: {adm}")
 
 
 
 
222
 
223
- # Gera combinações
224
- for r in range(1, min(max_cotas_combinacao + 1, len(cotas) + 1)):
225
- combinacoes_geradas = 0
226
- max_combinacoes_por_adm = 300
 
 
 
227
 
228
- for combinacao in itertools.combinations(cotas, r):
229
- if combinacoes_geradas >= max_combinacoes_por_adm:
230
  break
231
 
232
- total_combinacoes_testadas += 1
233
- combinacoes_geradas += 1
234
 
235
  total_credito = sum(c['valor_credito'] for c in combinacao)
236
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
@@ -247,34 +279,52 @@ def buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejad
247
 
248
  resultados.append((adm, combinacao, diferenca))
249
 
250
- if len(resultados) >= max_combinacoes * 2:
251
  break
252
-
253
- if len(resultados) >= max_combinacoes * 2:
254
- break
255
-
256
- if len(resultados) >= max_combinacoes * 2:
257
- break
258
 
259
- print(f"🔍 BUSCA AMPLA: Total de combinações testadas: {total_combinacoes_testadas}")
260
  print(f"🔍 BUSCA AMPLA: Combinações válidas encontradas: {len(resultados)}")
261
 
262
  if not resultados:
263
- return "🚫 Nenhuma combinação adequada encontrada com os parâmetros fornecidos."
 
264
 
265
  resultados.sort(key=lambda x: x[2])
266
  return formatar_resultados(resultados[:max_combinacoes])
267
 
268
- def formatar_moeda(valor):
269
- return f"R$ {valor:,.2f}".replace(",", "v").replace(".", ",").replace("v", ".")
270
-
271
- def formatar_resultados(resultados):
272
- """Formata os resultados para exibição."""
273
- if not resultados:
274
- return "🚫 Nenhuma combinação adequada encontrada com os parâmetros fornecidos."
 
 
 
 
275
 
276
- resposta = ""
277
- for idx, (adm, combinacao, _) in enumerate(resultados, 1):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
279
  total_credito = sum(c['valor_credito'] for c in combinacao)
280
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
@@ -289,22 +339,24 @@ def formatar_resultados(resultados):
289
  taxa_percentual = (taxa_total / credito_real) * 100 if credito_real > 0 else 0
290
  taxa_mensal = taxa_percentual / maior_prazo if maior_prazo > 0 else 0
291
 
292
- resposta += f"""
293
- --- COMBINAÇÃO {idx} ---
 
294
  🏢 Administradora: {adm}
295
  🔢 Códigos: {', '.join(codigos)} ({len(combinacao)} cotas)
296
- 💰 Crédito Total: {formatar_moeda(total_credito)}
297
- 💵 Entrada (+comissão): {formatar_moeda(total_entrada)}
 
298
  📉 Saldo Devedor: {formatar_moeda(total_saldo)}
299
- 💲 Parcela: {formatar_moeda(total_parcelas)}
300
  ⏳ Prazo: {maior_prazo} meses
301
  🔚 Valor Final: {formatar_moeda(valor_final)}
302
  💠 Crédito Líquido: {formatar_moeda(credito_real)}
303
  📊 Taxa Total: {taxa_percentual:.2f}% ({formatar_moeda(taxa_total)})
304
- 🗓️ Taxa Mensal: {taxa_mensal:.2f}%
305
- 🗓️ Taxa Anual: {taxa_mensal * 12:.2f}%
306
  """
307
- return resposta
 
308
 
309
  # Carrega a planilha uma vez quando o aplicativo inicia
310
  carregar_planilha()
 
92
 
93
  print(f"🔍 Total de administradoras no filtro: {len(grupos_filtrados)}")
94
 
95
+ # ANÁLISE DAS COTAS DISPONÍVEIS - CRÍTICO PARA VALORES ALTOS
96
+ todas_cotas = []
97
+ for adm, cotas in grupos_filtrados.items():
98
+ todas_cotas.extend(cotas)
99
+ print(f"📊 {adm}: {len(cotas)} cotas")
100
+
101
+ if not todas_cotas:
102
+ return "🚫 Nenhuma cota disponível para análise."
103
+
104
+ # Calcula estatísticas das cotas
105
+ creditos = [c['valor_credito'] for c in todas_cotas]
106
+ max_credito = max(creditos)
107
+ avg_credito = sum(creditos) / len(creditos)
108
+
109
+ print(f"📊 Estatísticas das cotas disponíveis:")
110
+ print(f"📊 Maior crédito individual: R$ {max_credito:,.2f}")
111
+ print(f"📊 Crédito médio: R$ {avg_credito:,.2f}")
112
+ print(f"📊 Total de cotas: {len(todas_cotas)}")
113
+
114
+ # TOLERÂNCIAS INTELIGENTES BASEADAS NAS ESTATÍSTICAS
115
+ # Para valores muito altos, aumentamos significativamente as tolerâncias
116
+ if credito_desejado > 1000000: # Acima de 1 milhão
117
+ # Quanto maior o valor, maior a tolerância necessária
118
+ fator_ajuste = min(1.0, credito_desejado / 5000000) # Normaliza entre 0 e 1
119
+
120
+ tolerancia_credito = 0.20 + (0.30 * fator_ajuste) # 20% a 50%
121
+ tolerancia_entrada = 0.20 + (0.25 * fator_ajuste) # 20% a 45%
122
+ tolerancia_parcela = 0.40 + (0.40 * fator_ajuste) # 40% a 80%
123
+
124
+ # Ajusta número máximo de cotas baseado na necessidade
125
+ cotas_estimadas = max(3, min(10, math.ceil(credito_desejado / avg_credito)))
126
+ max_cotas_combinacao = min(12, cotas_estimadas + 3)
127
  else:
128
+ tolerancia_credito = 0.10
129
+ tolerancia_entrada = 0.10
130
+ tolerancia_parcela = 0.30
131
+ max_cotas_combinacao = 4
132
 
133
  # Define faixas de tolerância
134
  credito_min = credito_desejado * (1 - tolerancia_credito)
 
145
  print(f"🔧 Faixas aceitáveis: Parcela: R$ {parcela_min:,.2f} - R$ {parcela_max:,.2f}")
146
  print(f"🔧 Máximo de cotas por combinação: {max_cotas_combinacao}")
147
 
148
+ # ESTRATÉGIA DE BUSCA OTIMIZADA PARA VALORES ALTOS
149
  resultados = []
 
150
 
151
+ # 1. PRIMEIRO: busca combinações progressivas por número de cotas
152
+ for num_cotas in range(1, max_cotas_combinacao + 1):
153
+ if len(resultados) >= max_combinacoes:
154
+ break
155
+
156
+ print(f"🔍 Buscando combinações com {num_cotas} cota(s)...")
 
157
 
158
+ for adm, cotas in grupos_filtrados.items():
159
+ if len(resultados) >= max_combinacoes:
160
+ break
161
+
162
+ # Para valores altos, prioriza cotas maiores primeiro
163
+ cotas_ordenadas = sorted(cotas, key=lambda x: x['valor_credito'], reverse=True)
164
+
165
+ # Limita o número de testes por administradora
166
+ max_testes = 150
167
+ testes_realizados = 0
168
 
169
+ for combinacao in itertools.combinations(cotas_ordenadas, num_cotas):
170
+ if testes_realizados >= max_testes:
171
  break
172
 
173
+ testes_realizados += 1
 
174
 
175
  total_credito = sum(c['valor_credito'] for c in combinacao)
176
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
 
188
 
189
  resultados.append((adm, combinacao, diferenca))
190
 
191
+ if len(resultados) >= max_combinacoes * 2:
 
192
  break
193
 
194
+ if len(resultados) >= max_combinacoes * 2:
195
  break
196
 
197
+ if len(resultados) >= max_combinacoes * 2:
198
  break
199
 
 
200
  print(f"🔍 Combinações válidas encontradas: {len(resultados)}")
201
 
202
+ # 2. SE NÃO ENCONTROU, TENTA BUSCA COM TOLERÂNCIAS MAIS AMPLAS
203
  if not resultados:
 
204
  print("🔍 Nenhuma combinação encontrada. Tentando busca ampla...")
205
  return buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejada, administradoras, max_combinacoes)
206
 
207
+ # 3. ORDENA E RETORNA OS MELHORES RESULTADOS
208
  resultados.sort(key=lambda x: x[2])
209
  return formatar_resultados(resultados[:max_combinacoes])
210
 
211
  def buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None, max_combinacoes=10):
212
+ """Busca combinações com tolerâncias extremamente amplas para valores altos."""
213
  global grupos_imovel
214
 
215
  # Filtra administradoras se especificado
 
218
  else:
219
  grupos_filtrados = grupos_imovel
220
 
221
+ # TOLERÂNCIAS MUITO AMPLAS ESPECIALMENTE PARA VALORES ALTOS
222
+ if credito_desejado > 1000000:
223
+ # Tolerâncias extremas para valores muito altos
224
+ tolerancia_credito = 0.50 # 50%
225
+ tolerancia_entrada = 0.50 # 50%
226
+ tolerancia_parcela = 1.00 # 100%
227
+ max_cotas_combinacao = 15 # Até 15 cotas por combinação
228
  else:
229
+ tolerancia_credito = 0.30
230
+ tolerancia_entrada = 0.30
231
+ tolerancia_parcela = 0.70
232
+ max_cotas_combinacao = 8
233
 
234
  credito_min = credito_desejado * (1 - tolerancia_credito)
235
  credito_max = credito_desejado * (1 + tolerancia_credito)
 
242
  print(f"🔍 BUSCA AMPLA: Máximo de cotas por combinação: {max_cotas_combinacao}")
243
 
244
  resultados = []
 
245
 
246
+ # Estratégia de busca mais agressiva
247
+ for num_cotas in range(2, max_cotas_combinacao + 1): # Começa com 2 cotas
248
+ if len(resultados) >= max_combinacoes:
249
+ break
250
+
251
+ print(f"🔍 BUSCA AMPLA - Procurando com {num_cotas} cotas...")
252
 
253
+ for adm, cotas in grupos_filtrados.items():
254
+ if len(resultados) >= max_combinacoes:
255
+ break
256
+
257
+ # Testa combinações de forma mais ampla
258
+ max_testes = 100
259
+ testes_realizados = 0
260
 
261
+ for combinacao in itertools.combinations(cotas, num_cotas):
262
+ if testes_realizados >= max_testes:
263
  break
264
 
265
+ testes_realizados += 1
 
266
 
267
  total_credito = sum(c['valor_credito'] for c in combinacao)
268
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
 
279
 
280
  resultados.append((adm, combinacao, diferenca))
281
 
282
+ if len(resultados) >= max_combinacoes:
283
  break
 
 
 
 
 
 
284
 
 
285
  print(f"🔍 BUSCA AMPLA: Combinações válidas encontradas: {len(resultados)}")
286
 
287
  if not resultados:
288
+ # Última tentativa: busca a combinação mais próxima possível
289
+ return gerar_sugestao_mais_proxima(credito_desejado, entrada_desejada, parcela_desejada, grupos_filtrados)
290
 
291
  resultados.sort(key=lambda x: x[2])
292
  return formatar_resultados(resultados[:max_combinacoes])
293
 
294
+ def gerar_sugestao_mais_proxima(credito_desejado, entrada_desejada, parcela_desejada, grupos_filtrados):
295
+ """Gera sugestão da combinação mais próxima quando não encontra resultados exatos."""
296
+ todas_cotas = []
297
+ for cotas in grupos_filtrados.values():
298
+ todas_cotas.extend(cotas)
299
+
300
+ if not todas_cotas:
301
+ return "🚫 Nenhuma cota disponível para análise."
302
+
303
+ melhor_combinacao = None
304
+ menor_diferenca = float('inf')
305
 
306
+ # Testa combinações de 2 a 10 cotas
307
+ for num_cotas in range(2, 11):
308
+ for adm, cotas in grupos_filtrados.items():
309
+ for combinacao in itertools.combinations(cotas, num_cotas):
310
+ total_credito = sum(c['valor_credito'] for c in combinacao)
311
+ total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
312
+ total_entrada = total_entrada_base + (total_credito * 0.085)
313
+ total_parcelas = sum(c['valor_parcela'] for c in combinacao)
314
+
315
+ # Calcula diferenças percentuais
316
+ diff_credito = abs(total_credito - credito_desejado) / credito_desejado
317
+ diff_entrada = abs(total_entrada - entrada_desejada) / entrada_desejada
318
+ diff_parcela = abs(total_parcelas - parcela_desejada) / parcela_desejada if parcela_desejada > 0 else 0
319
+
320
+ diferenca_total = diff_credito + diff_entrada + diff_parcela
321
+
322
+ if diferenca_total < menor_diferenca:
323
+ menor_diferenca = diferenca_total
324
+ melhor_combinacao = (adm, combinacao, diferenca_total)
325
+
326
+ if melhor_combinacao:
327
+ adm, combinacao, _ = melhor_combinacao
328
  codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
329
  total_credito = sum(c['valor_credito'] for c in combinacao)
330
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
 
339
  taxa_percentual = (taxa_total / credito_real) * 100 if credito_real > 0 else 0
340
  taxa_mensal = taxa_percentual / maior_prazo if maior_prazo > 0 else 0
341
 
342
+ return f"""
343
+ ⚠️ Nenhuma combinação exata encontrada, mas aqui está a mais próxima:
344
+
345
  🏢 Administradora: {adm}
346
  🔢 Códigos: {', '.join(codigos)} ({len(combinacao)} cotas)
347
+ 💰 Crédito Total: {formatar_moeda(total_credito)} (Desejado: {formatar_moeda(credito_desejado)})
348
+ 💵 Entrada: {formatar_moeda(total_entrada)} (Desejado: {formatar_moeda(entrada_desejada)})
349
+ 💲 Parcela: {formatar_moeda(total_parcelas)} (Desejado: {formatar_moeda(parcela_desejada)})
350
  📉 Saldo Devedor: {formatar_moeda(total_saldo)}
 
351
  ⏳ Prazo: {maior_prazo} meses
352
  🔚 Valor Final: {formatar_moeda(valor_final)}
353
  💠 Crédito Líquido: {formatar_moeda(credito_real)}
354
  📊 Taxa Total: {taxa_percentual:.2f}% ({formatar_moeda(taxa_total)})
355
+
356
+ 💡 Sugestão: Ajuste seus parâmetros ou considere múltiplas administradoras.
357
  """
358
+
359
+ return "🚫 Nenhuma combinação adequada encontrada com os parâmetros fornecidos."
360
 
361
  # Carrega a planilha uma vez quando o aplicativo inicia
362
  carregar_planilha()