diff --git a/app/apps/export_app/forms.py b/app/apps/export_app/forms.py new file mode 100644 index 0000000..69d36b5 --- /dev/null +++ b/app/apps/export_app/forms.py @@ -0,0 +1,80 @@ +from crispy_forms.bootstrap import FormActions +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Layout +from django import forms +from django.utils.translation import gettext_lazy as _ + +from apps.common.widgets.crispy.submit import NoClassSubmit + + +class ExportForm(forms.Form): + accounts = forms.BooleanField( + required=False, + widget=forms.CheckboxInput(), + label=_("Accounts"), + initial=True, + ) + currencies = forms.BooleanField( + required=False, + widget=forms.CheckboxInput(), + label=_("Currencies"), + initial=True, + ) + transactions = forms.BooleanField( + required=False, + widget=forms.CheckboxInput(), + label=_("Transactions"), + initial=True, + ) + categories = forms.BooleanField( + required=False, + widget=forms.CheckboxInput(), + label=_("Categories"), + initial=True, + ) + tags = forms.BooleanField( + required=False, + widget=forms.CheckboxInput(), + label=_("Tags"), + initial=False, + ) + entities = forms.BooleanField( + required=False, + widget=forms.CheckboxInput(), + label=_("Entities"), + initial=False, + ) + exchange_rates = forms.BooleanField( + required=False, + widget=forms.CheckboxInput(), + label=_("Exchange Rates"), + initial=False, + ) + exchange_rates_services = forms.BooleanField( + required=False, + widget=forms.CheckboxInput(), + label=_("Automatic Exchange Rates"), + initial=False, + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.helper = FormHelper() + self.helper.form_tag = False + self.helper.form_method = "post" + self.helper.layout = Layout( + "accounts", + "currencies", + "transactions", + "categories", + "entities", + "tags", + "exchange_rates_services", + "exchange_rates", + FormActions( + NoClassSubmit( + "submit", _("Export"), css_class="btn btn-outline-primary w-100" + ), + ), + ) diff --git a/app/apps/export_app/resources/accounts.py b/app/apps/export_app/resources/accounts.py new file mode 100644 index 0000000..e2c6cd0 --- /dev/null +++ b/app/apps/export_app/resources/accounts.py @@ -0,0 +1,25 @@ +from import_export import fields, resources, widgets + +from apps.accounts.models import Account +from apps.export_app.widgets.foreign_key import AutoCreateForeignKeyWidget + + +class AccountResource(resources.ModelResource): + group = fields.Field( + attribute="group", + column_name="group", + widget=AutoCreateForeignKeyWidget("accounts.AccountGroup", "name"), + ) + currency = fields.Field( + attribute="currency", + column_name="currency", + widget=widgets.ForeignKeyWidget("currencies.Currency", "name"), + ) + exchange_currency = fields.Field( + attribute="exchange_currency", + column_name="exchange_currency", + widget=widgets.ForeignKeyWidget("currencies.Currency", "name"), + ) + + class Meta: + model = Account diff --git a/app/apps/export_app/resources/currencies.py b/app/apps/export_app/resources/currencies.py new file mode 100644 index 0000000..698a528 --- /dev/null +++ b/app/apps/export_app/resources/currencies.py @@ -0,0 +1,46 @@ +from import_export import fields, resources, widgets + +from apps.currencies.models import Currency, ExchangeRate, ExchangeRateService + + +class CurrencyResource(resources.ModelResource): + exchange_currency = fields.Field( + attribute="exchange_currency", + column_name="exchange_currency", + widget=widgets.ForeignKeyWidget("currencies.Currency", "name"), + ) + + class Meta: + model = Currency + + +class ExchangeRateResource(resources.ModelResource): + from_currency = fields.Field( + attribute="from_currency", + column_name="from_currency", + widget=widgets.ForeignKeyWidget("currencies.Currency", "name"), + ) + to_currency = fields.Field( + attribute="to_currency", + column_name="to_currency", + widget=widgets.ForeignKeyWidget("currencies.Currency", "name"), + ) + + class Meta: + model = ExchangeRate + + +class ExchangeRateServiceResource(resources.ModelResource): + target_currencies = fields.Field( + attribute="target_currencies", + column_name="target_currencies", + widget=widgets.ManyToManyWidget("currencies.Currency", field="name"), + ) + target_accounts = fields.Field( + attribute="target_accounts", + column_name="target_accounts", + widget=widgets.ForeignKeyWidget("accounts.Account", field="name"), + ) + + class Meta: + model = ExchangeRateService diff --git a/app/apps/export_app/resources/transactions.py b/app/apps/export_app/resources/transactions.py index aca17c7..eb39c04 100644 --- a/app/apps/export_app/resources/transactions.py +++ b/app/apps/export_app/resources/transactions.py @@ -1,4 +1,5 @@ from import_export import fields, resources +from import_export.widgets import ForeignKeyWidget from apps.export_app.widgets.foreign_key import AutoCreateForeignKeyWidget from apps.export_app.widgets.many_to_many import AutoCreateManyToManyWidget @@ -14,7 +15,7 @@ class TransactionResource(resources.ModelResource): account = fields.Field( attribute="account", column_name="account", - widget=AutoCreateForeignKeyWidget("accounts.Account", "name"), + widget=ForeignKeyWidget("accounts.Account", "name"), ) category = fields.Field( @@ -37,3 +38,18 @@ class TransactionResource(resources.ModelResource): class Meta: model = Transaction + + +class TransactionTagResource(resources.ModelResource): + class Meta: + model = TransactionTag + + +class TransactionEntityResource(resources.ModelResource): + class Meta: + model = TransactionEntity + + +class TransactionCategoyResource(resources.ModelResource): + class Meta: + model = TransactionCategory diff --git a/app/apps/export_app/urls.py b/app/apps/export_app/urls.py index bfe4736..77a292a 100644 --- a/app/apps/export_app/urls.py +++ b/app/apps/export_app/urls.py @@ -2,5 +2,6 @@ from django.urls import path import apps.export_app.views as views urlpatterns = [ - path("export/", views.export, name="export"), + path("export/", views.export_index, name="export_index"), + path("export/export/", views.export_form, name="export_form"), ] diff --git a/app/apps/export_app/views.py b/app/apps/export_app/views.py index e950d8d..c8a7b33 100644 --- a/app/apps/export_app/views.py +++ b/app/apps/export_app/views.py @@ -1,9 +1,92 @@ +import zipfile +from io import BytesIO + +from django.http import HttpResponse from django.shortcuts import render -from apps.export_app.resources.transactions import TransactionResource +from apps.export_app.forms import ExportForm +from apps.export_app.resources.accounts import AccountResource +from apps.export_app.resources.transactions import ( + TransactionResource, + TransactionTagResource, + TransactionEntityResource, + TransactionCategoyResource, +) +from apps.export_app.resources.currencies import ( + CurrencyResource, + ExchangeRateResource, + ExchangeRateServiceResource, +) # Create your views here. -def export(request): +def export_index(request): dataset = TransactionResource().export() print(dataset.csv) + + +def export_form(request): + if request.method == "POST": + form = ExportForm(request.POST) + if form.is_valid(): + zip_buffer = BytesIO() + + export_accounts = form.cleaned_data.get("accounts", False) + export_currencies = form.cleaned_data.get("currencies", False) + export_transactions = form.cleaned_data.get("transactions", False) + export_categories = form.cleaned_data.get("categories", False) + export_tags = form.cleaned_data.get("tags", False) + export_entities = form.cleaned_data.get("entities", False) + export_exchange_rates_services = form.cleaned_data.get( + "exchange_rates_services", False + ) + export_exchange_rates = form.cleaned_data.get("exchange_rates", False) + + exports = [] + if export_accounts: + exports.append((AccountResource().export(), "accounts")) + if export_currencies: + exports.append((CurrencyResource().export(), "currencies")) + if export_transactions: + exports.append((TransactionResource().export(), "transactions")) + if export_tags: + exports.append((TransactionTagResource().export(), "transactions_tags")) + if export_entities: + exports.append( + (TransactionEntityResource().export(), "transactions_entities") + ) + if export_categories: + exports.append( + (TransactionCategoyResource().export(), "transactions_categories") + ) + if export_exchange_rates_services: + exports.append( + (ExchangeRateServiceResource().export(), "automatic_exchange_rates") + ) + if export_exchange_rates: + exports.append((ExchangeRateResource().export(), "exchange_rates")) + + if len(exports) >= 2: + with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file: + for dataset, name in exports: + zip_file.writestr(f"{name}.csv", dataset.csv) + + response = HttpResponse( + zip_buffer.getvalue(), content_type="application/zip" + ) + response["Content-Disposition"] = f'attachment; filename="export.zip"' + return response + else: + dataset, name = exports[0] + + response = HttpResponse( + dataset.csv, + content_type="text/csv", + ) + response["Content-Disposition"] = f'attachment; filename="{name}.csv"' + return response + + else: + form = ExportForm() + + return render(request, "export_app/pages/form.html", context={"form": form}) diff --git a/app/templates/export_app/pages/form.html b/app/templates/export_app/pages/form.html new file mode 100644 index 0000000..7144e99 --- /dev/null +++ b/app/templates/export_app/pages/form.html @@ -0,0 +1,13 @@ +{% extends "layouts/base.html" %} +{% load crispy_forms_tags %} +{% load i18n %} + +{% block title %}{% translate 'Import Profiles' %}{% endblock %} + +{% block content %} +