mirror of
https://github.com/ae-utbm/sith.git
synced 2024-12-22 07:41:14 +00:00
Convert customer refill to a fragment view
This commit is contained in:
parent
0f003870bb
commit
e9361697f7
@ -21,11 +21,12 @@ from ninja_extra import ControllerBase, api_controller, paginate, route
|
||||
from ninja_extra.pagination import PageNumberPaginationExtra
|
||||
from ninja_extra.schemas import PaginatedResponseSchema
|
||||
|
||||
from core.api_permissions import CanAccessLookup, CanView, IsRoot
|
||||
from counter.models import Counter, Product
|
||||
from core.api_permissions import CanAccessLookup, CanView, IsLoggedInCounter, IsRoot
|
||||
from counter.models import Counter, Customer, Product
|
||||
from counter.schemas import (
|
||||
CounterFilterSchema,
|
||||
CounterSchema,
|
||||
CustomerBalance,
|
||||
ProductSchema,
|
||||
SimplifiedCounterSchema,
|
||||
)
|
||||
@ -60,6 +61,13 @@ class CounterController(ControllerBase):
|
||||
return filters.filter(Counter.objects.all())
|
||||
|
||||
|
||||
@api_controller("/customer")
|
||||
class CustomerController(ControllerBase):
|
||||
@route.get("/balance", response=CustomerBalance, permissions=[IsLoggedInCounter])
|
||||
def get_balance(self, customer_id: int):
|
||||
return self.get_object_or_exception(Customer, pk=customer_id)
|
||||
|
||||
|
||||
@api_controller("/product")
|
||||
class ProductController(ControllerBase):
|
||||
@route.get(
|
||||
|
@ -4,7 +4,7 @@ from annotated_types import MinLen
|
||||
from ninja import Field, FilterSchema, ModelSchema
|
||||
|
||||
from core.schemas import SimpleUserSchema
|
||||
from counter.models import Counter, Product
|
||||
from counter.models import Counter, Customer, Product
|
||||
|
||||
|
||||
class CounterSchema(ModelSchema):
|
||||
@ -16,6 +16,12 @@ class CounterSchema(ModelSchema):
|
||||
fields = ["id", "name", "type", "club", "products"]
|
||||
|
||||
|
||||
class CustomerBalance(ModelSchema):
|
||||
class Meta:
|
||||
model = Customer
|
||||
fields = ["amount"]
|
||||
|
||||
|
||||
class CounterFilterSchema(FilterSchema):
|
||||
search: Annotated[str, MinLen(1)] = Field(None, q="name__icontains")
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block additional_js %}
|
||||
<script src="{{ static('counter/js/counter_click.js') }}" defer></script>
|
||||
<script type="module" src="{{ static('bundled/counter/counter-click-index.ts') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block info_boxes %}
|
||||
@ -28,7 +28,7 @@
|
||||
<h5>{% trans %}Customer{% endtrans %}</h5>
|
||||
{{ user_mini_profile(customer.user) }}
|
||||
{{ user_subscription(customer.user) }}
|
||||
<p>{% trans %}Amount: {% endtrans %}{{ customer.amount }} €</p>
|
||||
<p>{% trans %}Amount: {% endtrans %}<span x-text="customerBalance"></span> €</p>
|
||||
|
||||
{% if counter.type == 'BAR' %}
|
||||
<h5>{% trans %}Student card{% endtrans %}</h3>
|
||||
@ -105,16 +105,12 @@
|
||||
<input type="submit" value="{% trans %}Cancel{% endtrans %}"/>
|
||||
</form>
|
||||
</div>
|
||||
{% if (counter.type == 'BAR' and barmens_can_refill) %}
|
||||
{% if refilling_fragment %}
|
||||
<h5>{% trans %}Refilling{% endtrans %}</h5>
|
||||
<div>
|
||||
<form method="post"
|
||||
action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}">
|
||||
{% csrf_token %}
|
||||
{{ refill_form.as_p() }}
|
||||
<input type="hidden" name="action" value="refill">
|
||||
<input type="submit" value="{% trans %}Go{% endtrans %}"/>
|
||||
</form>
|
||||
<div
|
||||
@htmx:after-request="updateBalance()"
|
||||
>
|
||||
{{ refilling_fragment }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@ -155,9 +151,6 @@
|
||||
{% block script %}
|
||||
{{ super() }}
|
||||
<script>
|
||||
const csrfToken = "{{ csrf_token }}";
|
||||
const clickApiUrl = "{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}";
|
||||
const sessionBasket = {{ request.session["basket"]|tojson }};
|
||||
const products = {
|
||||
{%- for p in products -%}
|
||||
{{ p.id }}: {
|
||||
@ -176,5 +169,14 @@
|
||||
},
|
||||
{%- endfor %}
|
||||
];
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
loadCounter({
|
||||
csrfToken: "{{ csrf_token }}",
|
||||
clickApiUrl: "{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}",
|
||||
sessionBasket: {{ request.session["basket"]|tojson }},
|
||||
customerBalance: {{ customer.amount }},
|
||||
customerId: {{ customer.pk }},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock script %}
|
9
counter/templates/counter/fragments/create_refill.jinja
Normal file
9
counter/templates/counter/fragments/create_refill.jinja
Normal file
@ -0,0 +1,9 @@
|
||||
<form
|
||||
hx-trigger="submit"
|
||||
hx-post="{{ action }}"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<input type="submit" value="{% trans %}Go{% endtrans %}"/>
|
||||
</form>
|
@ -67,17 +67,24 @@ class TestCounter(TestCase):
|
||||
{"code": self.richard.customer.account_id, "counter_token": counter_token},
|
||||
)
|
||||
counter_url = response.get("location")
|
||||
response = self.client.get(response.get("location"))
|
||||
refill_url = reverse(
|
||||
"counter:refilling_create",
|
||||
kwargs={"customer_id": self.richard.customer.pk},
|
||||
)
|
||||
|
||||
response = self.client.get(
|
||||
response.get("location"),
|
||||
)
|
||||
assert ">Richard Batsbak</" in str(response.content)
|
||||
|
||||
self.client.post(
|
||||
counter_url,
|
||||
refill_url,
|
||||
{
|
||||
"action": "refill",
|
||||
"amount": "5",
|
||||
"payment_method": "CASH",
|
||||
"bank": "OTHER",
|
||||
},
|
||||
HTTP_REFERER=counter_url,
|
||||
)
|
||||
self.client.post(counter_url, "action=code&code=BARB", content_type="text/xml")
|
||||
self.client.post(
|
||||
@ -110,15 +117,15 @@ class TestCounter(TestCase):
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
counter_url,
|
||||
refill_url,
|
||||
{
|
||||
"action": "refill",
|
||||
"amount": "5",
|
||||
"payment_method": "CASH",
|
||||
"bank": "OTHER",
|
||||
},
|
||||
HTTP_REFERER=counter_url,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.status_code == 302
|
||||
|
||||
self.client.post(
|
||||
reverse("counter:login", kwargs={"counter_id": self.foyer.id}),
|
||||
@ -138,17 +145,23 @@ class TestCounter(TestCase):
|
||||
{"code": self.richard.customer.account_id, "counter_token": counter_token},
|
||||
)
|
||||
counter_url = response.get("location")
|
||||
refill_url = reverse(
|
||||
"counter:refilling_create",
|
||||
kwargs={
|
||||
"customer_id": self.richard.customer.pk,
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
counter_url,
|
||||
refill_url,
|
||||
{
|
||||
"action": "refill",
|
||||
"amount": "5",
|
||||
"payment_method": "CASH",
|
||||
"bank": "OTHER",
|
||||
},
|
||||
HTTP_REFERER=counter_url,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.status_code == 302
|
||||
|
||||
def test_annotate_has_barman_queryset(self):
|
||||
"""Test if the custom queryset method `annotate_has_barman` works as intended."""
|
||||
|
@ -39,7 +39,7 @@ from counter.views.cash import (
|
||||
CashSummaryListView,
|
||||
CounterCashSummaryView,
|
||||
)
|
||||
from counter.views.click import CounterClick
|
||||
from counter.views.click import CounterClick, RefillingCreateView
|
||||
from counter.views.eticket import (
|
||||
EticketCreateView,
|
||||
EticketEditView,
|
||||
@ -60,6 +60,11 @@ from counter.views.student_card import (
|
||||
urlpatterns = [
|
||||
path("<int:counter_id>/", CounterMain.as_view(), name="details"),
|
||||
path("<int:counter_id>/click/<int:user_id>/", CounterClick.as_view(), name="click"),
|
||||
path(
|
||||
"refill/<int:customer_id>/",
|
||||
RefillingCreateView.as_view(),
|
||||
name="refilling_create",
|
||||
),
|
||||
path(
|
||||
"<int:counter_id>/last_ops/",
|
||||
CounterLastOperationsView.as_view(),
|
||||
|
@ -24,11 +24,13 @@ from django.http import Http404, HttpResponseRedirect, JsonResponse
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import DetailView
|
||||
from django.views.generic import DetailView, FormView
|
||||
|
||||
from core.utils import FormFragmentTemplateData
|
||||
from core.views import CanViewMixin
|
||||
from counter.forms import RefillForm
|
||||
from counter.models import Counter, Customer, Product, Selling
|
||||
from counter.utils import is_logged_in_counter
|
||||
from counter.views.mixins import CounterTabsMixin
|
||||
from counter.views.student_card import StudentCardFormView
|
||||
|
||||
@ -100,7 +102,6 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
|
||||
request.session["too_young"] = False
|
||||
request.session["not_allowed"] = False
|
||||
request.session["no_age"] = False
|
||||
self.refill_form = None
|
||||
ret = super().get(request, *args, **kwargs)
|
||||
if (self.object.type != "BAR" and not request.user.is_authenticated) or (
|
||||
self.object.type == "BAR" and len(self.object.barmen_list) == 0
|
||||
@ -111,7 +112,6 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""Handle the many possibilities of the post request."""
|
||||
self.object = self.get_object()
|
||||
self.refill_form = None
|
||||
if (self.object.type != "BAR" and not request.user.is_authenticated) or (
|
||||
self.object.type == "BAR" and len(self.object.barmen_list) < 1
|
||||
): # Check that at least one barman is logged in
|
||||
@ -148,8 +148,6 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
|
||||
self.add_product(request)
|
||||
elif action == "del_product":
|
||||
self.del_product(request)
|
||||
elif action == "refill":
|
||||
self.refill(request)
|
||||
elif action == "code":
|
||||
return self.parse_code(request)
|
||||
elif action == "cancel":
|
||||
@ -383,19 +381,6 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
|
||||
reverse_lazy("counter:details", args=self.args, kwargs=kwargs)
|
||||
)
|
||||
|
||||
def refill(self, request):
|
||||
"""Refill the customer's account."""
|
||||
if not self.object.can_refill():
|
||||
raise PermissionDenied
|
||||
form = RefillForm(request.POST)
|
||||
if form.is_valid():
|
||||
form.instance.counter = self.object
|
||||
form.instance.operator = self.operator
|
||||
form.instance.customer = self.customer
|
||||
form.instance.save()
|
||||
else:
|
||||
self.refill_form = form
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""Add customer to the context."""
|
||||
kwargs = super().get_context_data(**kwargs)
|
||||
@ -413,9 +398,77 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
|
||||
)
|
||||
kwargs["customer"] = self.customer
|
||||
kwargs["basket_total"] = self.sum_basket(self.request)
|
||||
kwargs["refill_form"] = self.refill_form or RefillForm()
|
||||
kwargs["barmens_can_refill"] = self.object.can_refill()
|
||||
kwargs["student_card_fragment"] = StudentCardFormView.get_template_data(
|
||||
self.customer
|
||||
).render(self.request)
|
||||
|
||||
if self.object.can_refill():
|
||||
kwargs["refilling_fragment"] = RefillingCreateView.get_template_data(
|
||||
self.customer
|
||||
).render(self.request)
|
||||
return kwargs
|
||||
|
||||
|
||||
class RefillingCreateView(FormView):
|
||||
"""This is a fragment only view which integrates with counter_click.jinja"""
|
||||
|
||||
form_class = RefillForm
|
||||
template_name = "counter/fragments/create_refill.jinja"
|
||||
|
||||
@classmethod
|
||||
def get_template_data(
|
||||
cls, customer: Customer, *, form_instance: form_class | None = None
|
||||
) -> FormFragmentTemplateData[form_class]:
|
||||
return FormFragmentTemplateData[cls.form_class](
|
||||
form=form_instance if form_instance else cls.form_class(),
|
||||
template=cls.template_name,
|
||||
context={
|
||||
"action": reverse_lazy(
|
||||
"counter:refilling_create", kwargs={"customer_id": customer.pk}
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.customer: Customer = get_object_or_404(Customer, pk=kwargs["customer_id"])
|
||||
if not self.customer.can_buy:
|
||||
raise Http404
|
||||
|
||||
if not is_logged_in_counter(request):
|
||||
raise PermissionDenied
|
||||
|
||||
self.counter: Counter = get_object_or_404(
|
||||
Counter, token=request.session["counter_token"]
|
||||
)
|
||||
|
||||
if not self.counter.can_refill():
|
||||
raise PermissionDenied
|
||||
|
||||
if self.customer_is_barman():
|
||||
self.operator = self.customer.user
|
||||
else:
|
||||
self.operator = self.counter.get_random_barman()
|
||||
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def customer_is_barman(self) -> bool:
|
||||
barmen = self.counter.barmen_list
|
||||
return self.counter.type == "BAR" and self.customer.user in barmen
|
||||
|
||||
def form_valid(self, form):
|
||||
res = super().form_valid(form)
|
||||
form.clean()
|
||||
form.instance.counter = self.counter
|
||||
form.instance.operator = self.operator
|
||||
form.instance.customer = self.customer
|
||||
form.instance.save()
|
||||
return res
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
data = self.get_template_data(self.customer, form_instance=context["form"])
|
||||
context.update(data.context)
|
||||
return context
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
return self.request.path
|
||||
|
@ -70,11 +70,11 @@ class StudentCardFormView(FormView):
|
||||
|
||||
@classmethod
|
||||
def get_template_data(
|
||||
cls, customer: Customer
|
||||
) -> FormFragmentTemplateData[StudentCardForm]:
|
||||
cls, customer: Customer, *, form_instance: form_class | None = None
|
||||
) -> FormFragmentTemplateData[form_class]:
|
||||
"""Get necessary data to pre-render the fragment"""
|
||||
return FormFragmentTemplateData(
|
||||
form=cls.form_class(),
|
||||
return FormFragmentTemplateData[cls.form_class](
|
||||
form=form_instance if form_instance else cls.form_class(),
|
||||
template=cls.template_name,
|
||||
context={
|
||||
"action": reverse(
|
||||
@ -105,7 +105,7 @@ class StudentCardFormView(FormView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
data = self.get_template_data(self.customer)
|
||||
data = self.get_template_data(self.customer, form_instance=context["form"])
|
||||
context.update(data.context)
|
||||
return context
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user