| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- from django.contrib import messages
- from django.db.models.deletion import ProtectedError
- from django.shortcuts import redirect, render
- from django.urls import reverse_lazy
- from django.views.generic import CreateView, DeleteView, ListView, UpdateView
- from .forms import DividendoForm, DivisaForm, OperacionForm, ValorForm
- from .models import Dividendo, Divisa, Operacion, Valor
- from .services import (
- actualizar_cambios,
- actualizar_precios,
- desglose_fifo,
- posiciones,
- resumen_fiscal,
- totales,
- )
- class CancelarUrlMixin:
- """Aporta la URL de cancelación al formulario (vuelve atrás si hay referer)."""
- def get_context_data(self, **kwargs):
- ctx = super().get_context_data(**kwargs)
- ctx['cancelar_url'] = self.request.META.get('HTTP_REFERER') or str(self.success_url)
- return ctx
- def dashboard(request):
- pos = posiciones()
- context = {
- 'posiciones': pos,
- 'abiertas': [p for p in pos if p['acciones'] > 0],
- 'cerradas': [p for p in pos if p['acciones'] == 0],
- 'totales': totales(pos),
- }
- return render(request, 'cartera/dashboard.html', context)
- def actualizar(request):
- if request.method == 'POST':
- cambios, errores_cambios = actualizar_cambios()
- if cambios:
- messages.success(request, f'Cambios de moneda actualizados: {cambios}')
- for par, motivo in errores_cambios:
- messages.warning(request, f'{par}: {motivo}')
- correctos, errores = actualizar_precios()
- if correctos:
- messages.success(request, f'Precios actualizados: {correctos}')
- for ticker, motivo in errores:
- messages.warning(request, f'{ticker}: {motivo}')
- return redirect('cartera:dashboard')
- def fifo(request):
- filas = desglose_fifo()
- context = {
- 'filas': filas,
- 'fiscal': resumen_fiscal(filas),
- 'total': sum((f['resultado_eur'] or 0 for f in filas), start=0),
- }
- return render(request, 'cartera/fifo.html', context)
- class OperacionListView(ListView):
- model = Operacion
- template_name = 'cartera/operacion_list.html'
- context_object_name = 'operaciones'
- def get_queryset(self):
- qs = Operacion.objects.select_related('valor', 'valor__divisa').order_by('-fecha', '-pk')
- valor = self.request.GET.get('valor')
- if valor:
- qs = qs.filter(valor_id=valor)
- return qs
- def get_context_data(self, **kwargs):
- ctx = super().get_context_data(**kwargs)
- ctx['valores'] = Valor.objects.order_by('ticker')
- ctx['valor_filtro'] = self.request.GET.get('valor', '')
- return ctx
- class OperacionCreateView(CancelarUrlMixin, CreateView):
- model = Operacion
- form_class = OperacionForm
- template_name = 'cartera/form.html'
- success_url = reverse_lazy('cartera:operaciones')
- titulo = 'Nueva operación'
- def form_valid(self, form):
- messages.success(self.request, 'Operación registrada')
- return super().form_valid(form)
- class OperacionUpdateView(CancelarUrlMixin, UpdateView):
- model = Operacion
- form_class = OperacionForm
- template_name = 'cartera/form.html'
- success_url = reverse_lazy('cartera:operaciones')
- titulo = 'Editar operación'
- def form_valid(self, form):
- messages.success(self.request, 'Operación actualizada')
- return super().form_valid(form)
- class OperacionDeleteView(CancelarUrlMixin, DeleteView):
- model = Operacion
- template_name = 'cartera/confirm_delete.html'
- success_url = reverse_lazy('cartera:operaciones')
- titulo = 'Eliminar operación'
- def form_valid(self, form):
- messages.success(self.request, 'Operación eliminada')
- return super().form_valid(form)
- class DividendoListView(ListView):
- model = Dividendo
- template_name = 'cartera/dividendo_list.html'
- context_object_name = 'dividendos'
- queryset = Dividendo.objects.select_related('valor')
- class DividendoCreateView(CancelarUrlMixin, CreateView):
- model = Dividendo
- form_class = DividendoForm
- template_name = 'cartera/form.html'
- success_url = reverse_lazy('cartera:dividendos')
- titulo = 'Nuevo dividendo'
- def form_valid(self, form):
- messages.success(self.request, 'Dividendo registrado')
- return super().form_valid(form)
- class DividendoUpdateView(CancelarUrlMixin, UpdateView):
- model = Dividendo
- form_class = DividendoForm
- template_name = 'cartera/form.html'
- success_url = reverse_lazy('cartera:dividendos')
- titulo = 'Editar dividendo'
- def form_valid(self, form):
- messages.success(self.request, 'Dividendo actualizado')
- return super().form_valid(form)
- class DividendoDeleteView(CancelarUrlMixin, DeleteView):
- model = Dividendo
- template_name = 'cartera/confirm_delete.html'
- success_url = reverse_lazy('cartera:dividendos')
- titulo = 'Eliminar dividendo'
- def form_valid(self, form):
- messages.success(self.request, 'Dividendo eliminado')
- return super().form_valid(form)
- class ValorListView(ListView):
- model = Valor
- template_name = 'cartera/valor_list.html'
- context_object_name = 'valores'
- class ValorCreateView(CancelarUrlMixin, CreateView):
- model = Valor
- form_class = ValorForm
- template_name = 'cartera/form.html'
- success_url = reverse_lazy('cartera:valores')
- titulo = 'Nuevo valor'
- def form_valid(self, form):
- messages.success(self.request, 'Valor creado')
- return super().form_valid(form)
- class ValorUpdateView(CancelarUrlMixin, UpdateView):
- model = Valor
- form_class = ValorForm
- template_name = 'cartera/form.html'
- success_url = reverse_lazy('cartera:valores')
- titulo = 'Editar valor'
- def form_valid(self, form):
- messages.success(self.request, 'Valor actualizado')
- return super().form_valid(form)
- class ValorDeleteView(CancelarUrlMixin, DeleteView):
- model = Valor
- template_name = 'cartera/confirm_delete.html'
- success_url = reverse_lazy('cartera:valores')
- titulo = 'Eliminar valor'
- def form_valid(self, form):
- messages.success(self.request, 'Valor eliminado (con todas sus operaciones)')
- return super().form_valid(form)
- class DivisaListView(ListView):
- model = Divisa
- template_name = 'cartera/divisa_list.html'
- context_object_name = 'divisas'
- class DivisaCreateView(CancelarUrlMixin, CreateView):
- model = Divisa
- form_class = DivisaForm
- template_name = 'cartera/form.html'
- success_url = reverse_lazy('cartera:divisas')
- titulo = 'Nueva divisa'
- def form_valid(self, form):
- messages.success(self.request, 'Divisa creada')
- return super().form_valid(form)
- class DivisaUpdateView(CancelarUrlMixin, UpdateView):
- model = Divisa
- form_class = DivisaForm
- template_name = 'cartera/form.html'
- success_url = reverse_lazy('cartera:divisas')
- titulo = 'Editar divisa'
- def form_valid(self, form):
- messages.success(self.request, 'Divisa actualizada')
- return super().form_valid(form)
- class DivisaDeleteView(CancelarUrlMixin, DeleteView):
- model = Divisa
- template_name = 'cartera/confirm_delete.html'
- success_url = reverse_lazy('cartera:divisas')
- titulo = 'Eliminar divisa'
- def post(self, request, *args, **kwargs):
- try:
- return super().post(request, *args, **kwargs)
- except ProtectedError:
- messages.error(
- request,
- 'No se puede eliminar: hay valores que usan esta divisa.',
- )
- return redirect('cartera:divisas')
|