diff --git a/expenses_manager/expenses/forms.py b/expenses_manager/expenses/forms.py index d5f6ae9..0cfdb77 100644 --- a/expenses_manager/expenses/forms.py +++ b/expenses_manager/expenses/forms.py @@ -1,4 +1,5 @@ from django import forms +from .csv_export import DEFAULT_DIALECT from .models import ( Expense, Category, @@ -233,5 +234,66 @@ class GoalForm(forms.ModelForm): ) else: cleaned["period"] = Goal.PERIOD_NONE - + + return cleaned + + +class ExportForm(forms.Form): + """Filtros de la exportación a CSV. Valida la pantalla y la descarga. + + Los filtros son a propósito solo rango de fechas y cuenta: la gracia de un + CSV es filtrar fuera, y duplicar aquí la fila de filtros avanzados de + expense_list serían dos UIs que divergen. + """ + + KIND_CHOICES = [ + ("expenses", "Gastos"), + ("incomes", "Ingresos"), + ("transfers", "Traspasos"), + ] + FMT_CHOICES = [ + ("excel", "Excel español — separador ; y decimales con coma"), + ("std", "CSV estándar — separador , y decimales con punto"), + ] + + kind = forms.ChoiceField(choices=KIND_CHOICES, label="Qué exportar") + date_from = forms.DateField( + required=False, + label="Desde", + widget=forms.DateInput(format="%Y-%m-%d", attrs={"type": "date"}), + ) + date_to = forms.DateField( + required=False, + label="Hasta", + widget=forms.DateInput(format="%Y-%m-%d", attrs={"type": "date"}), + ) + account = forms.ModelChoiceField( + queryset=Account.objects.none(), + required=False, + label="Cuenta", + empty_label="Todas las cuentas", + ) + fmt = forms.ChoiceField( + choices=FMT_CHOICES, label="Formato", initial=DEFAULT_DIALECT + ) + + def __init__(self, *args, **kwargs): + user = kwargs.pop("user") + super().__init__(*args, **kwargs) + + # Activas e inactivas: se exporta histórico, y una cuenta cerrada tiene + # movimientos que interesan. + self.fields["account"].queryset = Account.objects.filter(owner=user) + self.fields["date_from"].input_formats = ["%Y-%m-%d"] + self.fields["date_to"].input_formats = ["%Y-%m-%d"] + + def clean(self): + cleaned = super().clean() + date_from, date_to = cleaned.get("date_from"), cleaned.get("date_to") + + # En un listado un rango invertido se ignora; aquí no, porque el + # resultado sería un fichero vacío descargado sin explicación. + if date_from and date_to and date_from > date_to: + self.add_error("date_to", "La fecha final es anterior a la inicial.") + return cleaned \ No newline at end of file diff --git a/expenses_manager/expenses/templates/expenses/base.html b/expenses_manager/expenses/templates/expenses/base.html index 0da53aa..6c24746 100644 --- a/expenses_manager/expenses/templates/expenses/base.html +++ b/expenses_manager/expenses/templates/expenses/base.html @@ -43,6 +43,7 @@ Categorías Etiquetas Objetivos + Exportar datos diff --git a/expenses_manager/expenses/templates/expenses/export_form.html b/expenses_manager/expenses/templates/expenses/export_form.html new file mode 100644 index 0000000..d1efec2 --- /dev/null +++ b/expenses_manager/expenses/templates/expenses/export_form.html @@ -0,0 +1,30 @@ +{% extends "expenses/base.html" %} + +{% block title %}Exportar datos{% endblock %} + +{% block content %} +
Descarga tus movimientos en CSV para abrirlos en Excel o tratarlos aparte.
+ + + + +{% endblock %} diff --git a/expenses_manager/expenses/templates/settings/index.html b/expenses_manager/expenses/templates/settings/index.html index 9b9e81e..29eaf4e 100644 --- a/expenses_manager/expenses/templates/settings/index.html +++ b/expenses_manager/expenses/templates/settings/index.html @@ -24,6 +24,11 @@Define y controla tus metas de gasto.
+ + +Descarga tus gastos, ingresos o traspasos en CSV.
+ {% endblock %} \ No newline at end of file diff --git a/expenses_manager/expenses/urls.py b/expenses_manager/expenses/urls.py index fbb07fa..252b3d7 100644 --- a/expenses_manager/expenses/urls.py +++ b/expenses_manager/expenses/urls.py @@ -33,6 +33,8 @@ urlpatterns = [ path('categories/