#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# You can find the source code of the website at https://github.com/ae-utbm/sith
#
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
#

import collections

from django import forms
from django.conf import settings
from django.core.exceptions import PermissionDenied, ValidationError
from django.db import transaction
from django.db.models import Sum
from django.forms import HiddenInput
from django.forms.models import modelform_factory
from django.http import HttpResponse
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView

from accounting.models import (
    AccountingType,
    BankAccount,
    ClubAccount,
    Company,
    GeneralJournal,
    Label,
    Operation,
    SimplifiedAccountingType,
)
from accounting.widgets.select import (
    AutoCompleteSelectClubAccount,
    AutoCompleteSelectCompany,
)
from club.models import Club
from club.widgets.select import AutoCompleteSelectClub
from core.models import User
from core.views import (
    CanCreateMixin,
    CanEditMixin,
    CanEditPropMixin,
    CanViewMixin,
    TabedViewMixin,
)
from core.views.forms import SelectDate, SelectFile
from core.views.widgets.select import AutoCompleteSelectUser
from counter.models import Counter, Product, Selling

# Main accounting view


class BankAccountListView(CanViewMixin, ListView):
    """A list view for the admins."""

    model = BankAccount
    template_name = "accounting/bank_account_list.jinja"
    ordering = ["name"]


# Simplified accounting types


class SimplifiedAccountingTypeListView(CanViewMixin, ListView):
    """A list view for the admins."""

    model = SimplifiedAccountingType
    template_name = "accounting/simplifiedaccountingtype_list.jinja"


class SimplifiedAccountingTypeEditView(CanViewMixin, UpdateView):
    """An edit view for the admins."""

    model = SimplifiedAccountingType
    pk_url_kwarg = "type_id"
    fields = ["label", "accounting_type"]
    template_name = "core/edit.jinja"


class SimplifiedAccountingTypeCreateView(CanCreateMixin, CreateView):
    """Create an accounting type (for the admins)."""

    model = SimplifiedAccountingType
    fields = ["label", "accounting_type"]
    template_name = "core/create.jinja"


# Accounting types


class AccountingTypeListView(CanViewMixin, ListView):
    """A list view for the admins."""

    model = AccountingType
    template_name = "accounting/accountingtype_list.jinja"


class AccountingTypeEditView(CanViewMixin, UpdateView):
    """An edit view for the admins."""

    model = AccountingType
    pk_url_kwarg = "type_id"
    fields = ["code", "label", "movement_type"]
    template_name = "core/edit.jinja"


class AccountingTypeCreateView(CanCreateMixin, CreateView):
    """Create an accounting type (for the admins)."""

    model = AccountingType
    fields = ["code", "label", "movement_type"]
    template_name = "core/create.jinja"


# BankAccount views


class BankAccountEditView(CanViewMixin, UpdateView):
    """An edit view for the admins."""

    model = BankAccount
    pk_url_kwarg = "b_account_id"
    fields = ["name", "iban", "number", "club"]
    template_name = "core/edit.jinja"


class BankAccountDetailView(CanViewMixin, DetailView):
    """A detail view, listing every club account."""

    model = BankAccount
    pk_url_kwarg = "b_account_id"
    template_name = "accounting/bank_account_details.jinja"


class BankAccountCreateView(CanCreateMixin, CreateView):
    """Create a bank account (for the admins)."""

    model = BankAccount
    fields = ["name", "club", "iban", "number"]
    template_name = "core/create.jinja"


class BankAccountDeleteView(
    CanEditPropMixin, DeleteView
):  # TODO change Delete to Close
    """Delete a bank account (for the admins)."""

    model = BankAccount
    pk_url_kwarg = "b_account_id"
    template_name = "core/delete_confirm.jinja"
    success_url = reverse_lazy("accounting:bank_list")


# ClubAccount views


class ClubAccountEditView(CanViewMixin, UpdateView):
    """An edit view for the admins."""

    model = ClubAccount
    pk_url_kwarg = "c_account_id"
    fields = ["name", "club", "bank_account"]
    template_name = "core/edit.jinja"


class ClubAccountDetailView(CanViewMixin, DetailView):
    """A detail view, listing every journal."""

    model = ClubAccount
    pk_url_kwarg = "c_account_id"
    template_name = "accounting/club_account_details.jinja"


class ClubAccountCreateView(CanCreateMixin, CreateView):
    """Create a club account (for the admins)."""

    model = ClubAccount
    fields = ["name", "club", "bank_account"]
    template_name = "core/create.jinja"

    def get_initial(self):
        ret = super().get_initial()
        if "parent" in self.request.GET:
            obj = BankAccount.objects.filter(id=int(self.request.GET["parent"])).first()
            if obj is not None:
                ret["bank_account"] = obj.id
        return ret


class ClubAccountDeleteView(
    CanEditPropMixin, DeleteView
):  # TODO change Delete to Close
    """Delete a club account (for the admins)."""

    model = ClubAccount
    pk_url_kwarg = "c_account_id"
    template_name = "core/delete_confirm.jinja"
    success_url = reverse_lazy("accounting:bank_list")


# Journal views


class JournalTabsMixin(TabedViewMixin):
    def get_tabs_title(self):
        return _("Journal")

    def get_list_of_tabs(self):
        return [
            {
                "url": reverse(
                    "accounting:journal_details", kwargs={"j_id": self.object.id}
                ),
                "slug": "journal",
                "name": _("Journal"),
            },
            {
                "url": reverse(
                    "accounting:journal_nature_statement",
                    kwargs={"j_id": self.object.id},
                ),
                "slug": "nature_statement",
                "name": _("Statement by nature"),
            },
            {
                "url": reverse(
                    "accounting:journal_person_statement",
                    kwargs={"j_id": self.object.id},
                ),
                "slug": "person_statement",
                "name": _("Statement by person"),
            },
            {
                "url": reverse(
                    "accounting:journal_accounting_statement",
                    kwargs={"j_id": self.object.id},
                ),
                "slug": "accounting_statement",
                "name": _("Accounting statement"),
            },
        ]


class JournalCreateView(CanCreateMixin, CreateView):
    """Create a general journal."""

    model = GeneralJournal
    form_class = modelform_factory(
        GeneralJournal,
        fields=["name", "start_date", "club_account"],
        widgets={"start_date": SelectDate},
    )
    template_name = "core/create.jinja"

    def get_initial(self):
        ret = super().get_initial()
        if "parent" in self.request.GET:
            obj = ClubAccount.objects.filter(id=int(self.request.GET["parent"])).first()
            if obj is not None:
                ret["club_account"] = obj.id
        return ret


class JournalDetailView(JournalTabsMixin, CanViewMixin, DetailView):
    """A detail view, listing every operation."""

    model = GeneralJournal
    pk_url_kwarg = "j_id"
    template_name = "accounting/journal_details.jinja"
    current_tab = "journal"


class JournalEditView(CanEditMixin, UpdateView):
    """Update a general journal."""

    model = GeneralJournal
    pk_url_kwarg = "j_id"
    fields = ["name", "start_date", "end_date", "club_account", "closed"]
    template_name = "core/edit.jinja"


class JournalDeleteView(CanEditPropMixin, DeleteView):
    """Delete a club account (for the admins)."""

    model = GeneralJournal
    pk_url_kwarg = "j_id"
    template_name = "core/delete_confirm.jinja"
    success_url = reverse_lazy("accounting:club_details")

    def dispatch(self, request, *args, **kwargs):
        self.object = self.get_object()
        if self.object.operations.count() == 0:
            return super().dispatch(request, *args, **kwargs)
        else:
            raise PermissionDenied


# Operation views


class OperationForm(forms.ModelForm):
    class Meta:
        model = Operation
        fields = [
            "amount",
            "remark",
            "journal",
            "target_type",
            "target_id",
            "target_label",
            "date",
            "mode",
            "cheque_number",
            "invoice",
            "simpleaccounting_type",
            "accounting_type",
            "label",
            "done",
        ]
        widgets = {
            "journal": HiddenInput,
            "target_id": HiddenInput,
            "date": SelectDate,
            "invoice": SelectFile,
        }

    user = forms.ModelChoiceField(
        help_text=None,
        required=False,
        widget=AutoCompleteSelectUser,
        queryset=User.objects.all(),
    )
    club_account = forms.ModelChoiceField(
        help_text=None,
        required=False,
        widget=AutoCompleteSelectClubAccount,
        queryset=ClubAccount.objects.all(),
    )
    club = forms.ModelChoiceField(
        help_text=None,
        required=False,
        widget=AutoCompleteSelectClub,
        queryset=Club.objects.all(),
    )
    company = forms.ModelChoiceField(
        help_text=None,
        required=False,
        widget=AutoCompleteSelectCompany,
        queryset=Company.objects.all(),
    )
    need_link = forms.BooleanField(
        label=_("Link this operation to the target account"),
        required=False,
        initial=False,
    )

    def __init__(self, *args, **kwargs):
        club_account = kwargs.pop("club_account", None)
        super().__init__(*args, **kwargs)
        if club_account:
            self.fields["label"].queryset = club_account.labels.order_by("name").all()
        if self.instance.target_type == "USER":
            self.fields["user"].initial = self.instance.target_id
        elif self.instance.target_type == "ACCOUNT":
            self.fields["club_account"].initial = self.instance.target_id
        elif self.instance.target_type == "CLUB":
            self.fields["club"].initial = self.instance.target_id
        elif self.instance.target_type == "COMPANY":
            self.fields["company"].initial = self.instance.target_id

    def clean(self):
        self.cleaned_data = super().clean()
        if "target_type" in self.cleaned_data:
            if (
                self.cleaned_data.get("user") is None
                and self.cleaned_data.get("club") is None
                and self.cleaned_data.get("club_account") is None
                and self.cleaned_data.get("company") is None
                and self.cleaned_data.get("target_label") == ""
            ):
                self.add_error(
                    "target_type", ValidationError(_("The target must be set."))
                )
            else:
                if self.cleaned_data["target_type"] == "USER":
                    self.cleaned_data["target_id"] = self.cleaned_data["user"].id
                elif self.cleaned_data["target_type"] == "ACCOUNT":
                    self.cleaned_data["target_id"] = self.cleaned_data[
                        "club_account"
                    ].id
                elif self.cleaned_data["target_type"] == "CLUB":
                    self.cleaned_data["target_id"] = self.cleaned_data["club"].id
                elif self.cleaned_data["target_type"] == "COMPANY":
                    self.cleaned_data["target_id"] = self.cleaned_data["company"].id

        if self.cleaned_data.get("amount") is None:
            self.add_error("amount", ValidationError(_("The amount must be set.")))

        return self.cleaned_data

    def save(self):
        ret = super().save()
        if (
            self.instance.target_type == "ACCOUNT"
            and not self.instance.linked_operation
            and self.instance.target.has_open_journal()
            and self.cleaned_data["need_link"]
        ):
            inst = self.instance
            club_account = inst.target
            acc_type = (
                AccountingType.objects.exclude(movement_type="NEUTRAL")
                .exclude(movement_type=inst.accounting_type.movement_type)
                .order_by("code")
                .first()
            )  # Select a random opposite accounting type
            op = Operation(
                journal=club_account.get_open_journal(),
                amount=inst.amount,
                date=inst.date,
                remark=inst.remark,
                mode=inst.mode,
                cheque_number=inst.cheque_number,
                invoice=inst.invoice,
                done=False,  # Has to be checked by hand
                simpleaccounting_type=None,
                accounting_type=acc_type,
                target_type="ACCOUNT",
                target_id=inst.journal.club_account.id,
                target_label="",
                linked_operation=inst,
            )
            op.save()
            self.instance.linked_operation = op
            self.save()
        return ret


class OperationCreateView(CanCreateMixin, CreateView):
    """Create an operation."""

    model = Operation
    form_class = OperationForm
    template_name = "accounting/operation_edit.jinja"

    def get_form(self, form_class=None):
        self.journal = GeneralJournal.objects.filter(id=self.kwargs["j_id"]).first()
        ca = self.journal.club_account if self.journal else None
        return self.form_class(club_account=ca, **self.get_form_kwargs())

    def get_initial(self):
        ret = super().get_initial()
        if self.journal is not None:
            ret["journal"] = self.journal.id
        return ret

    def get_context_data(self, **kwargs):
        """Add journal to the context."""
        kwargs = super().get_context_data(**kwargs)
        if self.journal:
            kwargs["object"] = self.journal
        return kwargs


class OperationEditView(CanEditMixin, UpdateView):
    """An edit view, working as detail for the moment."""

    model = Operation
    pk_url_kwarg = "op_id"
    form_class = OperationForm
    template_name = "accounting/operation_edit.jinja"

    def get_context_data(self, **kwargs):
        """Add journal to the context."""
        kwargs = super().get_context_data(**kwargs)
        kwargs["object"] = self.object.journal
        return kwargs


class OperationPDFView(CanViewMixin, DetailView):
    """Display the PDF of a given operation."""

    model = Operation
    pk_url_kwarg = "op_id"

    def get(self, request, *args, **kwargs):
        from reportlab.lib import colors
        from reportlab.lib.pagesizes import letter
        from reportlab.lib.units import cm
        from reportlab.lib.utils import ImageReader
        from reportlab.pdfbase import pdfmetrics
        from reportlab.pdfbase.ttfonts import TTFont
        from reportlab.pdfgen import canvas
        from reportlab.platypus import Table, TableStyle

        pdfmetrics.registerFont(TTFont("DejaVu", "DejaVuSerif.ttf"))

        self.object = self.get_object()
        amount = self.object.amount
        remark = self.object.remark
        nature = self.object.accounting_type.movement_type
        num = self.object.number
        date = self.object.date
        mode = self.object.mode
        club_name = self.object.journal.club_account.name
        ti = self.object.journal.name
        op_label = self.object.label
        club_address = self.object.journal.club_account.club.address
        id_op = self.object.id

        if self.object.target_type == "OTHER":
            target = self.object.target_label
        else:
            target = self.object.target.get_display_name()

        response = HttpResponse(content_type="application/pdf")
        response["Content-Disposition"] = 'filename="op-%d(%s_on_%s).pdf"' % (
            num,
            ti,
            club_name,
        )
        p = canvas.Canvas(response)

        p.setFont("DejaVu", 12)

        p.setTitle("%s %d" % (_("Operation"), num))
        width, height = letter
        im = ImageReader("core/static/core/img/logo.jpg")
        iw, ih = im.getSize()
        p.drawImage(im, 40, height - 50, width=iw / 2, height=ih / 2)

        labelStr = [["%s %s - %s %s" % (_("Journal"), ti, _("Operation"), num)]]

        label = Table(labelStr, colWidths=[150], rowHeights=[20])

        label.setStyle(TableStyle([("ALIGN", (0, 0), (-1, -1), "RIGHT")]))
        w, h = label.wrapOn(label, 0, 0)
        label.drawOn(p, width - 180, height)

        p.drawString(
            90, height - 100, _("Financial proof: ") + "OP%010d" % (id_op)
        )  # Justificatif du libellé
        p.drawString(
            90, height - 130, _("Club: %(club_name)s") % ({"club_name": club_name})
        )
        p.drawString(
            90,
            height - 160,
            _("Label: %(op_label)s")
            % {"op_label": op_label if op_label is not None else ""},
        )
        p.drawString(90, height - 190, _("Date: %(date)s") % {"date": date})

        data = []

        data += [
            ["%s" % (_("Credit").upper() if nature == "CREDIT" else _("Debit").upper())]
        ]

        data += [[_("Amount: %(amount).2f €") % {"amount": amount}]]

        payment_mode = ""
        for m in settings.SITH_ACCOUNTING_PAYMENT_METHOD:
            if m[0] == mode:
                payment_mode += "[\u00d7]"
            else:
                payment_mode += "[  ]"
            payment_mode += " %s\n" % (m[1])

        data += [[payment_mode]]

        data += [
            [
                "%s : %s"
                % (_("Debtor") if nature == "CREDIT" else _("Creditor"), target),
                "",
            ]
        ]

        data += [["%s \n%s" % (_("Comment:"), remark)]]

        t = Table(
            data, colWidths=[(width - 90 * 2) / 2] * 2, rowHeights=[20, 20, 70, 20, 80]
        )
        t.setStyle(
            TableStyle(
                [
                    ("ALIGN", (0, 0), (-1, -1), "CENTER"),
                    ("VALIGN", (-2, -1), (-1, -1), "TOP"),
                    ("VALIGN", (0, 0), (-1, -2), "MIDDLE"),
                    ("INNERGRID", (0, 0), (-1, -1), 0.25, colors.black),
                    ("SPAN", (0, 0), (1, 0)),  # line DEBIT/CREDIT
                    ("SPAN", (0, 1), (1, 1)),  # line amount
                    ("SPAN", (-2, -1), (-1, -1)),  # line comment
                    ("SPAN", (0, -2), (-1, -2)),  # line creditor/debtor
                    ("SPAN", (0, 2), (1, 2)),  # line payment_mode
                    ("ALIGN", (0, 2), (1, 2), "LEFT"),  # line payment_mode
                    ("ALIGN", (-2, -1), (-1, -1), "LEFT"),
                    ("BOX", (0, 0), (-1, -1), 0.25, colors.black),
                ]
            )
        )

        signature = []
        signature += [[_("Signature:")]]

        tSig = Table(signature, colWidths=[(width - 90 * 2)], rowHeights=[80])
        tSig.setStyle(
            TableStyle(
                [
                    ("VALIGN", (0, 0), (-1, -1), "TOP"),
                    ("BOX", (0, 0), (-1, -1), 0.25, colors.black),
                ]
            )
        )

        w, h = tSig.wrapOn(p, 0, 0)
        tSig.drawOn(p, 90, 200)

        w, h = t.wrapOn(p, 0, 0)

        t.drawOn(p, 90, 350)

        p.drawCentredString(10.5 * cm, 2 * cm, club_name)
        p.drawCentredString(10.5 * cm, 1 * cm, club_address)

        p.showPage()
        p.save()
        return response


class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView):
    """Display a statement sorted by labels."""

    model = GeneralJournal
    pk_url_kwarg = "j_id"
    template_name = "accounting/journal_statement_nature.jinja"
    current_tab = "nature_statement"

    def statement(self, queryset, movement_type):
        ret = collections.OrderedDict()
        statement = collections.OrderedDict()
        total_sum = 0
        for sat in [
            None,
            *list(SimplifiedAccountingType.objects.order_by("label")),
        ]:
            amount = queryset.filter(
                accounting_type__movement_type=movement_type, simpleaccounting_type=sat
            ).aggregate(amount_sum=Sum("amount"))["amount_sum"]
            label = sat.label if sat is not None else ""
            if amount:
                total_sum += amount
                statement[label] = amount
        ret[movement_type] = statement
        ret[movement_type + "_sum"] = total_sum
        return ret

    def big_statement(self):
        label_list = (
            self.object.operations.order_by("label").values_list("label").distinct()
        )
        labels = Label.objects.filter(id__in=label_list).all()
        statement = collections.OrderedDict()
        gen_statement = collections.OrderedDict()
        no_label_statement = collections.OrderedDict()
        gen_statement.update(self.statement(self.object.operations.all(), "CREDIT"))
        gen_statement.update(self.statement(self.object.operations.all(), "DEBIT"))
        statement[_("General statement")] = gen_statement
        no_label_statement.update(
            self.statement(self.object.operations.filter(label=None).all(), "CREDIT")
        )
        no_label_statement.update(
            self.statement(self.object.operations.filter(label=None).all(), "DEBIT")
        )
        statement[_("No label operations")] = no_label_statement
        for label in labels:
            l_stmt = collections.OrderedDict()
            journals = self.object.operations.filter(label=label).all()
            l_stmt.update(self.statement(journals, "CREDIT"))
            l_stmt.update(self.statement(journals, "DEBIT"))
            statement[label] = l_stmt
        return statement

    def get_context_data(self, **kwargs):
        """Add infos to the context."""
        kwargs = super().get_context_data(**kwargs)
        kwargs["statement"] = self.big_statement()
        return kwargs


class JournalPersonStatementView(JournalTabsMixin, CanViewMixin, DetailView):
    """Calculate a dictionary with operation target and sum of operations."""

    model = GeneralJournal
    pk_url_kwarg = "j_id"
    template_name = "accounting/journal_statement_person.jinja"
    current_tab = "person_statement"

    def sum_by_target(self, target_id, target_type, movement_type):
        return self.object.operations.filter(
            accounting_type__movement_type=movement_type,
            target_id=target_id,
            target_type=target_type,
        ).aggregate(amount_sum=Sum("amount"))["amount_sum"]

    def statement(self, movement_type):
        statement = collections.OrderedDict()
        for op in (
            self.object.operations.filter(accounting_type__movement_type=movement_type)
            .order_by("target_type", "target_id")
            .distinct()
        ):
            statement[op.target] = self.sum_by_target(
                op.target_id, op.target_type, movement_type
            )
        return statement

    def total(self, movement_type):
        return sum(self.statement(movement_type).values())

    def get_context_data(self, **kwargs):
        """Add journal to the context."""
        kwargs = super().get_context_data(**kwargs)
        kwargs["credit_statement"] = self.statement("CREDIT")
        kwargs["debit_statement"] = self.statement("DEBIT")
        kwargs["total_credit"] = self.total("CREDIT")
        kwargs["total_debit"] = self.total("DEBIT")
        return kwargs


class JournalAccountingStatementView(JournalTabsMixin, CanViewMixin, DetailView):
    """Calculate a dictionary with operation type and sum of operations."""

    model = GeneralJournal
    pk_url_kwarg = "j_id"
    template_name = "accounting/journal_statement_accounting.jinja"
    current_tab = "accounting_statement"

    def statement(self):
        statement = collections.OrderedDict()
        for at in AccountingType.objects.order_by("code").all():
            sum_by_type = self.object.operations.filter(
                accounting_type__code__startswith=at.code
            ).aggregate(amount_sum=Sum("amount"))["amount_sum"]
            if sum_by_type:
                statement[at] = sum_by_type
        return statement

    def get_context_data(self, **kwargs):
        """Add journal to the context."""
        kwargs = super().get_context_data(**kwargs)
        kwargs["statement"] = self.statement()
        return kwargs


# Company views


class CompanyListView(CanViewMixin, ListView):
    model = Company
    template_name = "accounting/co_list.jinja"


class CompanyCreateView(CanCreateMixin, CreateView):
    """Create a company."""

    model = Company
    fields = ["name"]
    template_name = "core/create.jinja"
    success_url = reverse_lazy("accounting:co_list")


class CompanyEditView(CanCreateMixin, UpdateView):
    """Edit a company."""

    model = Company
    pk_url_kwarg = "co_id"
    fields = ["name"]
    template_name = "core/edit.jinja"
    success_url = reverse_lazy("accounting:co_list")


# Label views


class LabelListView(CanViewMixin, DetailView):
    model = ClubAccount
    pk_url_kwarg = "clubaccount_id"
    template_name = "accounting/label_list.jinja"


class LabelCreateView(
    CanCreateMixin, CreateView
):  # FIXME we need to check the rights before creating the object
    model = Label
    form_class = modelform_factory(
        Label, fields=["name", "club_account"], widgets={"club_account": HiddenInput}
    )
    template_name = "core/create.jinja"

    def get_initial(self):
        ret = super().get_initial()
        if "parent" in self.request.GET:
            obj = ClubAccount.objects.filter(id=int(self.request.GET["parent"])).first()
            if obj is not None:
                ret["club_account"] = obj.id
        return ret


class LabelEditView(CanEditMixin, UpdateView):
    model = Label
    pk_url_kwarg = "label_id"
    fields = ["name"]
    template_name = "core/edit.jinja"


class LabelDeleteView(CanEditMixin, DeleteView):
    model = Label
    pk_url_kwarg = "label_id"
    template_name = "core/delete_confirm.jinja"

    def get_success_url(self):
        return self.object.get_absolute_url()


class CloseCustomerAccountForm(forms.Form):
    user = forms.ModelChoiceField(
        label=_("Refound this account"),
        help_text=None,
        required=True,
        widget=AutoCompleteSelectUser,
        queryset=User.objects.all(),
    )


class RefoundAccountView(FormView):
    """Create a selling with the same amount than the current user money."""

    template_name = "accounting/refound_account.jinja"
    form_class = CloseCustomerAccountForm

    def permission(self, user):
        if user.is_root or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
            return True
        else:
            raise PermissionDenied

    def dispatch(self, request, *arg, **kwargs):
        res = super().dispatch(request, *arg, **kwargs)
        if self.permission(request.user):
            return res

    def post(self, request, *arg, **kwargs):
        self.operator = request.user
        if self.permission(request.user):
            return super().post(self, request, *arg, **kwargs)

    def form_valid(self, form):
        self.customer = form.cleaned_data["user"]
        self.create_selling()
        return super().form_valid(form)

    def get_success_url(self):
        return reverse("accounting:refound_account")

    def create_selling(self):
        with transaction.atomic():
            uprice = self.customer.customer.amount
            refound_club_counter = Counter.objects.get(
                id=settings.SITH_COUNTER_REFOUND_ID
            )
            refound_club = refound_club_counter.club
            s = Selling(
                label=_("Refound account"),
                unit_price=uprice,
                quantity=1,
                seller=self.operator,
                customer=self.customer.customer,
                club=refound_club,
                counter=refound_club_counter,
                product=Product.objects.get(id=settings.SITH_PRODUCT_REFOUND_ID),
            )
            s.save()