max amount for eboutic refills

This commit is contained in:
imperosol
2026-06-11 14:21:50 +02:00
parent 39bbbc8878
commit d41a3a524a
7 changed files with 97 additions and 40 deletions
@@ -5,10 +5,11 @@ interface BasketItem {
name: string;
quantity: number;
unitPrice: number;
isRefill: boolean;
}
const BASKET_CACHE_KEY = "basket";
const BASKET_CACHE_VERSION = 1;
const BASKET_CACHE_VERSION = 2;
document.addEventListener("alpine:init", () => {
Alpine.data("basket", (validPrices: number[], lastPurchaseTime?: number) => ({
@@ -21,7 +22,7 @@ document.addEventListener("alpine:init", () => {
});
document
.getElementById("id_form-TOTAL_FORMS")
.setAttribute(":value", "basket.length");
?.setAttribute(":value", "basket.length");
},
loadBasket(): BasketItem[] {
@@ -32,8 +33,8 @@ document.addEventListener("alpine:init", () => {
return [];
}
if (
lastPurchaseTime !== null &&
localStorage.basketTimestamp !== undefined &&
lastPurchaseTime &&
localStorage.basketTimestamp &&
new Date(lastPurchaseTime) >=
new Date(Number.parseInt(localStorage.basketTimestamp, 10))
) {
@@ -64,6 +65,15 @@ document.addEventListener("alpine:init", () => {
);
},
getTotalRefill() {
return this.basket
.filter((item) => item.isRefill)
.reduce(
(acc: number, item: BasketItem) => acc + item.quantity * item.unitPrice,
0,
);
},
/**
* Add 1 to the quantity of an item in the basket
* @param {BasketItem} item
@@ -86,7 +96,7 @@ document.addEventListener("alpine:init", () => {
if (this.basket[index].quantity === 0) {
this.basket = this.basket.filter(
(e: BasketItem) => e.priceId !== this.basket[index].id,
(e: BasketItem) => e.priceId !== this.basket[index].priceId,
);
}
},
@@ -103,14 +113,16 @@ document.addEventListener("alpine:init", () => {
* @param id The id of the product to add
* @param name The name of the product
* @param price The unit price of the product
* @param isRefill true if the product is a refill bond
* @returns The created item
*/
createItem(id: number, name: string, price: number): BasketItem {
createItem(id: number, name: string, price: number, isRefill: boolean): BasketItem {
const newItem = {
priceId: id,
name,
quantity: 0,
unitPrice: price,
isRefill,
} as BasketItem;
this.basket.push(newItem);
@@ -125,16 +137,17 @@ document.addEventListener("alpine:init", () => {
* @param id The id of the product to add
* @param name The name of the product
* @param price The unit price of the product
* @param isRefill true if the product is a refill bond
*/
addFromCatalog(id: number, name: string, price: number) {
let item = this.basket.find((e: BasketItem) => e.priceId === id);
addFromCatalog(id: number, name: string, price: number, isRefill: boolean) {
const item = this.basket.find((e: BasketItem) => e.priceId === id);
// if the item is not in the basket, we create it
// else we add + 1 to it
if (item) {
this.add(item);
} else {
item = this.createItem(id, name, price);
this.createItem(id, name, price, isRefill);
}
},
}));
+22 -3
View File
@@ -58,6 +58,17 @@
</div>
</div>
{% endif %}
<template x-if="(getTotalRefill() + {{ customer_amount }}) > {{ settings.SITH_ACCOUNT_MAX_MONEY }}">
<div class="alert alert-red">
<div class="alert-main">
{% trans trimmed limit=settings.SITH_ACCOUNT_MAX_MONEY %}
You cannot purchase the current basket,
because it would put your AE account balance
above the {{ limit }}€ limit
{% endtrans %}
</div>
</div>
</template>
<ul class="item-list">
{# Starting money #}
<li>
@@ -109,9 +120,12 @@
<i class="fa fa-trash"></i>
{% trans %}Clear{% endtrans %}
</button>
<button class="btn btn-blue">
<button
class="btn btn-blue"
:disabled="(getTotalRefill() + {{ customer_amount }}) > {{ settings.SITH_ACCOUNT_MAX_MONEY }}"
>
<i class="fa fa-check"></i>
<input type="submit" value="{% trans %}Validate{% endtrans %}"/>
{% trans %}Validate{% endtrans %}
</button>
</div>
</form>
@@ -199,7 +213,12 @@
id="{{ price.id }}"
class="card clickable shadow"
:class="{selected: basket.some((i) => i.priceId === {{ price.id }})}"
@click='addFromCatalog({{ price.id }}, {{ price.full_label|tojson }}, {{ price.amount }})'
@click='addFromCatalog(
{{ price.id }},
{{ price.full_label|tojson }},
{{ price.amount }},
{{ (price.product.product_type_id == settings.SITH_COUNTER_PRODUCTTYPE_REFILLING)|lower }}
)'
{% if price.sold_out %}disabled{% endif %}
>
{% if price.product.icon %}
+25 -5
View File
@@ -70,6 +70,26 @@ class BaseEbouticBasketForm(BaseBasketForm):
# Disable money check
...
def _check_refills(self):
"""Check that this basket won't put customer balance above the limit."""
refill_type_id = settings.SITH_COUNTER_PRODUCTTYPE_REFILLING
total_refill = sum(
f.price.amount * f.cleaned_data["quantity"]
for f in self.forms
if f.price.product.product_type_id == refill_type_id
)
total_other = sum(
f.price.amount * f.cleaned_data["quantity"]
for f in self.forms
if f.price.product.product_type_id != refill_type_id
)
limit = settings.SITH_ACCOUNT_MAX_MONEY
if (total_refill - total_other + self.customer.amount) > limit:
raise ValidationError(
_("There cannot be more than %(money)d€ on an AE account")
% {"money": limit}
)
EbouticBasketForm = forms.formset_factory(
BasketItemForm, formset=BaseEbouticBasketForm, absolute_max=None, min_num=1
@@ -88,15 +108,15 @@ class EbouticMainView(LoginRequiredMixin, FormView):
form_class = EbouticBasketForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["form_kwargs"] = {
return super().get_form_kwargs() | {
"customer": self.customer,
"counter": get_eboutic(),
"allowed_prices": {
price.id: price for price in self.prices if not price.sold_out
"form_kwargs": {
"allowed_prices": {
price.id: price for price in self.prices if not price.sold_out
}
},
}
return kwargs
def form_valid(self, formset):
if len(formset) == 0: