Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • AlekSIS/onboarding/AlekSIS-App-Tezor
  • sunweaver/AlekSIS-App-Tezor
  • 3lisvequii/AlekSIS-App-Tezor
3 results
Show changes
Commits on Source (6)
Showing
with 450 additions and 10 deletions
from material import Layout, Row
from aleksis.core.mixins import ExtensibleForm
from .models.base import Client
from .models.invoice import InvoiceGroup
class EditClientForm(ExtensibleForm):
"""Form to create or edit clients."""
layout = Layout("name")
class Meta:
model = Client
exclude = []
class EditInvoiceGroupForm(ExtensibleForm):
layout = Layout(
Row("name", "template_name")
)
class Meta:
model = InvoiceGroup
exclude = ["client"]
from django.utils.translation import gettext_lazy as _
MENUS = {
"NAV_MENU_CORE": [
{
"name": _("Payments"),
"url": "#",
"root": True,
"icon": "price_check",
"validators": [
"menu_generator.validators.is_authenticated",
"aleksis.core.util.core_helpers.has_person",
],
"submenu": [
{
"name": _("Clients"),
"url": "clients",
"icon": "account_balance",
"validators": [
(
"aleksis.core.util.predicates.permission_validator",
"tezor.can_view_clients",
)
],
},
],
}
]
}
......@@ -11,3 +11,6 @@ class Client(ExtensibleModel):
constraints = [
models.UniqueConstraint(fields=["name", "site"], name="uniq_client_per_site")
]
def __str__(self) -> str:
return self.name
......@@ -21,6 +21,10 @@ class InvoiceGroup(ExtensibleModel):
template_name = models.CharField(verbose_name=_("Template to render invoices with as PDF"), blank=True, max_length=255)
def __str__(self) -> str:
return self.name
class Meta:
constraints = [
models.UniqueConstraint(fields=["client", "name"], name="group_uniq_per_client")
......
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables
from django_tables2.utils import A
class PurchasedItemsTable(tables.Table):
......@@ -32,3 +33,73 @@ class TotalsTable(tables.Table):
class Meta:
show_header = False
orderable = False
class ClientsTable(tables.Table):
class Meta:
attrs = {"class": "responsive-table highlight"}
name = tables.Column()
view = tables.LinkColumn(
"client_by_pk",
args=[A("id")],
verbose_name=_("View"),
text=_("View"),
)
edit = tables.LinkColumn(
"edit_client_by_pk",
args=[A("id")],
verbose_name=_("Edit"),
text=_("Edit"),
)
delete = tables.LinkColumn(
"delete_client_by_pk",
args=[A("id")],
verbose_name=_("Delete"),
text=_("Delete"),
)
class InvoiceGroupsTable(tables.Table):
name = tables.Column()
template_name = tables.Column()
view = tables.LinkColumn(
"invoice_group_by_pk",
args=[A("id")],
verbose_name=_("View"),
text=_("View"),
)
edit = tables.LinkColumn(
"edit_invoice_group_by_pk",
args=[A("id")],
verbose_name=_("Edit"),
text=_("Edit"),
)
delete = tables.LinkColumn(
"delete_invoice_group_by_pk",
args=[A("id")],
verbose_name=_("Delete"),
text=_("Delete"),
)
class InvoicesTable(tables.Table):
transaction_id = tables.Column()
status = tables.Column()
created = tables.DateColumn()
billing_first_name = tables.Column()
billing_last_name = tables.Column()
total = tables.Column()
view = tables.LinkColumn(
"invoice_by_pk",
args=[A("id")],
verbose_name=_("View"),
text=_("View"),
)
print = tables.LinkColumn(
"get_invoice_by_pk",
args=[A("id")],
verbose_name=_("Print"),
text=_("Print"),
)
{% extends "core/base.html" %}
{% load material_form i18n %}
{% block page_title %}{% blocktrans %}Create client{% endblocktrans %}{% endblock %}
{% block browser_title %}{% blocktrans %}Create client{% endblocktrans %}{% endblock %}
{% block extra_head %}
{{ form.media.css }}
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{% form form=form %}{% endform %}
{% include "core/partials/save_button.html" %}
</form>
{{ form.media.js }}
{% endblock %}
{% extends "core/base.html" %}
{% load material_form i18n %}
{% block page_title %}{% blocktrans %}Edit client{% endblocktrans %}{% endblock %}
{% block browser_title %}{% blocktrans %}Edit client{% endblocktrans %}{% endblock %}
{% block extra_head %}
{{ form.media.css }}
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{% form form=form %}{% endform %}
{% include "core/partials/save_button.html" %}
</form>
{{ form.media.js }}
{% endblock %}
{% extends "core/base.html" %}
{% load material_form i18n %}
{% load render_table from django_tables2 %}
{% block page_title %}{% blocktrans %}Client{% endblocktrans %} {{ client }}{% endblock %}
{% block browser_title %}{% blocktrans %}Client{% endblocktrans %} {{ client }}{% endblock %}
{% block content %}
<a class="btn colour-primary waves-effect waves-light" href="{% url 'create_invoice_group' client.id %}">{% trans "Add invoice group" %}</a>
{% render_table invoice_groups_table %}
{% endblock %}
{% extends "core/base.html" %}
{% load material_form i18n %}
{% load render_table from django_tables2 %}
{% block page_title %}{% blocktrans %}Clients{% endblocktrans %}{% endblock %}
{% block browser_title %}{% blocktrans %}Clients{% endblocktrans %}{% endblock %}
{% block content %}
<a class="btn colour-primary waves-effect waves-light" href="{% url 'create_client' %}">{% trans "Create client" %}</a>
{% render_table table %}
{% endblock %}
{% extends 'core/base.html' %}
{% load i18n %}
{% block content %}
<p class="flow-text">
{% blocktrans %}Tezor (account and payment system){% endblocktrans %}
</p>
{% endblock %}
{% extends "core/base.html" %}
{% load material_form i18n %}
{% load render_table from django_tables2 %}
{% block browser_title %}{{ object.transaction_id }}{% endblock %}
{% block content %}
<h1>{% trans "Invoice" %} {{ object.transaction_id }} — {{ object.created.date }}</h1>
<a class="btn colour-primary waves-effect waves-light" href="{% url 'invoice_group_by_pk' object.group.pk %}">{% trans "Back" %}</a>
{% render_table object.purchased_items_table %}
{% render_table object.totals_table %}
{% endblock %}
{% extends "core/base.html" %}
{% load material_form i18n %}
{% block page_title %}{% blocktrans %}Create invoice group{% endblocktrans %}{% endblock %}
{% block browser_title %}{% blocktrans %}Create invoice group{% endblocktrans %}{% endblock %}
{% block extra_head %}
{{ form.media.css }}
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{% form form=form %}{% endform %}
{% include "core/partials/save_button.html" %}
</form>
{{ form.media.js }}
{% endblock %}
{% extends "core/base.html" %}
{% load material_form i18n %}
{% block page_title %}{% blocktrans %}Edit invoice group{% endblocktrans %}{% endblock %}
{% block browser_title %}{% blocktrans %}Edit invoice group{% endblocktrans %}{% endblock %}
{% block extra_head %}
{{ form.media.css }}
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{% form form=form %}{% endform %}
{% include "core/partials/save_button.html" %}
</form>
{{ form.media.js }}
{% endblock %}
{% extends "core/base.html" %}
{% load material_form i18n %}
{% load render_table from django_tables2 %}
{% block page_title %}{{ object }}{% endblock %}
{% block browser_title %}{{ object }}{% endblock %}
{% block content %}
<a class="btn colour-primary waves-effect waves-light" href="{% url 'client_by_pk' object.client.pk %}">{% trans "Back" %}</a>
{% render_table invoices_table %}
{% endblock %}
......@@ -4,5 +4,55 @@ from . import views
urlpatterns = [
path("payments/", include("payments.urls")),
path("invoice/<int:pk>/print", views.GetInvoicePDF.as_view(), name="get_invoice_by_pk")
path("invoice/<int:pk>/print", views.GetInvoicePDF.as_view(), name="get_invoice_by_pk"),
path(
"clients/list",
views.ClientListView.as_view(),
name="clients",
),
path(
"clients/create",
views.ClientCreateView.as_view(),
name="create_client",
),
path(
"clients/<int:pk>/edit",
views.ClientEditView.as_view(),
name="edit_client_by_pk",
),
path(
"clients/<int:pk>/delete",
views.ClientDeleteView.as_view(),
name="delete_client_by_pk",
),
path(
"clients/<int:pk>/",
views.ClientDetailView.as_view(),
name="client_by_pk",
),
path(
"client/<int:pk>/invoice_groups/create",
views.InvoiceGroupCreateView.as_view(),
name="create_invoice_group",
),
path(
"invoice_groups/<int:pk>/edit",
views.InvoiceGroupEditView.as_view(),
name="edit_invoice_group_by_pk",
),
path(
"invoice_groups/<int:pk>/",
views.InvoiceGroupDetailView.as_view(),
name="invoice_group_by_pk",
),
path(
"invoice_groups/<int:pk>/delete",
views.InvoiceGroupDeleteView.as_view(),
name="delete_invoice_group_by_pk",
),
path(
"invoice/<int:pk>/",
views.InvoiceDetailView.as_view(),
name="invoice_by_pk",
),
]
from django.views.generic import View
from django.shortcuts import render
from django.views.decorators.cache import never_cache
from django.utils.decorators import method_decorator
from django.views.generic import FormView, TemplateView
from django.utils.translation import ugettext as _
from django.urls import reverse, reverse_lazy
from django.views.generic.detail import DetailView
from rules.contrib.views import PermissionRequiredMixin
from django_tables2.views import SingleTableView, RequestConfig
from aleksis.core.views import RenderPDFView
from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView
from .models.invoice import Invoice
from .tables import ClientsTable, InvoiceGroupsTable, InvoicesTable
from .forms import EditClientForm, EditInvoiceGroupForm
from .models.base import Client
from .models.invoice import Invoice, InvoiceGroup
class GetInvoicePDF(PermissionRequiredMixin, RenderPDFView):
......@@ -20,3 +31,125 @@ class GetInvoicePDF(PermissionRequiredMixin, RenderPDFView):
print(invoice.group.__dict__)
return context
class ClientListView(PermissionRequiredMixin, SingleTableView):
"""Table of all clients."""
model = Client
table_class = ClientsTable
permission_required = "tezor.view_clients"
template_name = "tezor/client/list.html"
@method_decorator(never_cache, name="dispatch")
class ClientCreateView(PermissionRequiredMixin, AdvancedCreateView):
"""Create view for clients."""
model = Client
form_class = EditClientForm
permission_required = "tezor.add_clients"
template_name = "tezor/client/create.html"
success_url = reverse_lazy("clients")
success_message = _("The client has been created.")
@method_decorator(never_cache, name="dispatch")
class ClientEditView(PermissionRequiredMixin, AdvancedEditView):
"""Edit view for clients."""
model = Client
form_class = EditClientForm
permission_required = "tezor.edit_clients"
template_name = "tezor/client/edit.html"
success_url = reverse_lazy("clients")
success_message = _("The client has been saved.")
class ClientDeleteView(PermissionRequiredMixin, AdvancedDeleteView):
"""Delete view for client."""
model = Client
permission_required = "tezor.delete_client"
template_name = "core/pages/delete.html"
success_url = reverse_lazy("clients")
success_message = _("The client has been deleted.")
class ClientDetailView(PermissionRequiredMixin, DetailView):
model = Client
permission_required = "tezor.view_client"
template_name = "tezor/client/full.html"
def get_context_data(self, object):
context = super().get_context_data()
invoice_groups = object.invoice_groups.all()
invoice_groups_table = InvoiceGroupsTable(invoice_groups)
RequestConfig(self.request).configure(invoice_groups_table)
context["invoice_groups_table"] = invoice_groups_table
return context
class InvoiceGroupDetailView(PermissionRequiredMixin, DetailView):
model = InvoiceGroup
permission_required = "tezor.view_invoice_group"
template_name = "tezor/invoice_group/full.html"
def get_context_data(self, object):
context = super().get_context_data()
invoices = object.invoices.all()
invoices_table = InvoicesTable(invoices)
RequestConfig(self.request).configure(invoices_table)
context["invoices_table"] = invoices_table
return context
@method_decorator(never_cache, name="dispatch")
class InvoiceGroupCreateView(PermissionRequiredMixin, AdvancedCreateView):
"""Create view for invoice_groups."""
model = InvoiceGroup
form_class = EditInvoiceGroupForm
permission_required = "tezor.add_invoice_groups"
template_name = "tezor/invoice_group/create.html"
success_url = reverse_lazy("clients")
success_message = _("The invoice_group has been created.")
def form_valid(self, form):
client = Client.objects.get(id=self.kwargs["pk"])
InvoiceGroup.objects.create(client=client, name=form.cleaned_data["name"], template_name=form.cleaned_data["template_name"])
return super().form_valid(form)
@method_decorator(never_cache, name="dispatch")
class InvoiceGroupEditView(PermissionRequiredMixin, AdvancedEditView):
"""Edit view for invoice_groups."""
model = InvoiceGroup
form_class = EditInvoiceGroupForm
permission_required = "tezor.edit_invoice_groups"
template_name = "tezor/invoice_group/edit.html"
success_url = reverse_lazy("invoice_groups")
success_message = _("The invoice_group has been saved.")
class InvoiceGroupDeleteView(PermissionRequiredMixin, AdvancedDeleteView):
"""Delete view for invoice_group."""
model = InvoiceGroup
permission_required = "tezor.delete_invoice_group"
template_name = "core/pages/delete.html"
success_url = reverse_lazy("invoice_groups")
success_message = _("The invoice_group has been deleted.")
class InvoiceDetailView(PermissionRequiredMixin, DetailView):
model = Invoice
permission_required = "tezor.view_invoice"
template_name = "tezor/invoice/full.html"