mirror of
https://github.com/ae-utbm/sith.git
synced 2025-12-11 07:35:59 +00:00
automatically apply formulas on click
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
import { AlertMessage } from "#core:utils/alert-message";
|
import { AlertMessage } from "#core:utils/alert-message";
|
||||||
import { BasketItem } from "#counter:counter/basket";
|
import { BasketItem } from "#counter:counter/basket";
|
||||||
import type { CounterConfig, ErrorMessage } from "#counter:counter/types";
|
import type {
|
||||||
|
CounterConfig,
|
||||||
|
ErrorMessage,
|
||||||
|
ProductFormula,
|
||||||
|
} from "#counter:counter/types";
|
||||||
import type { CounterProductSelect } from "./components/counter-product-select-index.ts";
|
import type { CounterProductSelect } from "./components/counter-product-select-index.ts";
|
||||||
|
|
||||||
document.addEventListener("alpine:init", () => {
|
document.addEventListener("alpine:init", () => {
|
||||||
@@ -47,15 +51,43 @@ document.addEventListener("alpine:init", () => {
|
|||||||
|
|
||||||
this.basket[id] = item;
|
this.basket[id] = item;
|
||||||
|
|
||||||
|
this.checkFormulas();
|
||||||
|
|
||||||
if (this.sumBasket() > this.customerBalance) {
|
if (this.sumBasket() > this.customerBalance) {
|
||||||
item.quantity = oldQty;
|
item.quantity = oldQty;
|
||||||
if (item.quantity === 0) {
|
if (item.quantity === 0) {
|
||||||
delete this.basket[id];
|
delete this.basket[id];
|
||||||
}
|
}
|
||||||
return gettext("Not enough money");
|
this.alertMessage.display(gettext("Not enough money"), { success: false });
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
return "";
|
checkFormulas() {
|
||||||
|
const products = new Set(
|
||||||
|
Object.keys(this.basket).map((i: string) => Number.parseInt(i)),
|
||||||
|
);
|
||||||
|
const formula: ProductFormula = config.formulas.find((f: ProductFormula) => {
|
||||||
|
return f.products.every((p: number) => products.has(p));
|
||||||
|
});
|
||||||
|
if (formula === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const product of formula.products) {
|
||||||
|
const key = product.toString();
|
||||||
|
this.basket[key].quantity -= 1;
|
||||||
|
if (this.basket[key].quantity <= 0) {
|
||||||
|
this.removeFromBasket(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.alertMessage.display(
|
||||||
|
interpolate(
|
||||||
|
gettext("Formula %(formula)s applied"),
|
||||||
|
{ formula: config.products[formula.result.toString()].name },
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
{ success: true },
|
||||||
|
);
|
||||||
|
this.addToBasket(formula.result.toString(), 1);
|
||||||
},
|
},
|
||||||
|
|
||||||
getBasketSize() {
|
getBasketSize() {
|
||||||
@@ -70,14 +102,7 @@ document.addEventListener("alpine:init", () => {
|
|||||||
(acc: number, cur: BasketItem) => acc + cur.sum(),
|
(acc: number, cur: BasketItem) => acc + cur.sum(),
|
||||||
0,
|
0,
|
||||||
) as number;
|
) as number;
|
||||||
return total;
|
return Math.round(total * 100) / 100;
|
||||||
},
|
|
||||||
|
|
||||||
addToBasketWithMessage(id: string, quantity: number) {
|
|
||||||
const message = this.addToBasket(id, quantity);
|
|
||||||
if (message.length > 0) {
|
|
||||||
this.alertMessage.display(message, { success: false });
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onRefillingSuccess(event: CustomEvent) {
|
onRefillingSuccess(event: CustomEvent) {
|
||||||
@@ -116,7 +141,7 @@ document.addEventListener("alpine:init", () => {
|
|||||||
this.finish();
|
this.finish();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.addToBasketWithMessage(code, quantity);
|
this.addToBasket(code, quantity);
|
||||||
}
|
}
|
||||||
this.codeField.widget.clear();
|
this.codeField.widget.clear();
|
||||||
this.codeField.widget.focus();
|
this.codeField.widget.focus();
|
||||||
|
|||||||
6
counter/static/bundled/counter/types.d.ts
vendored
6
counter/static/bundled/counter/types.d.ts
vendored
@@ -7,10 +7,16 @@ export interface InitialFormData {
|
|||||||
errors?: string[];
|
errors?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProductFormula {
|
||||||
|
result: number;
|
||||||
|
products: number[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface CounterConfig {
|
export interface CounterConfig {
|
||||||
customerBalance: number;
|
customerBalance: number;
|
||||||
customerId: number;
|
customerId: number;
|
||||||
products: Record<string, Product>;
|
products: Record<string, Product>;
|
||||||
|
formulas: ProductFormula[];
|
||||||
formInitial: InitialFormData[];
|
formInitial: InitialFormData[];
|
||||||
cancelUrl: string;
|
cancelUrl: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,12 @@
|
|||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.basket-error-container {
|
.basket-message-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block
|
display: block
|
||||||
}
|
}
|
||||||
|
|
||||||
.basket-error {
|
.basket-message {
|
||||||
z-index: 10; // to get on top of tomselect
|
z-index: 10; // to get on top of tomselect
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -32,13 +32,11 @@
|
|||||||
<div id="bar-ui" x-data="counter({
|
<div id="bar-ui" x-data="counter({
|
||||||
customerBalance: {{ customer.amount }},
|
customerBalance: {{ customer.amount }},
|
||||||
products: products,
|
products: products,
|
||||||
|
formulas: formulas,
|
||||||
customerId: {{ customer.pk }},
|
customerId: {{ customer.pk }},
|
||||||
formInitial: formInitial,
|
formInitial: formInitial,
|
||||||
cancelUrl: '{{ cancel_url }}',
|
cancelUrl: '{{ cancel_url }}',
|
||||||
})">
|
})">
|
||||||
<noscript>
|
|
||||||
<p class="important">Javascript is required for the counter UI.</p>
|
|
||||||
</noscript>
|
|
||||||
|
|
||||||
<div id="user_info">
|
<div id="user_info">
|
||||||
<h5>{% trans %}Customer{% endtrans %}</h5>
|
<h5>{% trans %}Customer{% endtrans %}</h5>
|
||||||
@@ -88,11 +86,12 @@
|
|||||||
|
|
||||||
<form x-cloak method="post" action="" x-ref="basketForm">
|
<form x-cloak method="post" action="" x-ref="basketForm">
|
||||||
|
|
||||||
<div class="basket-error-container">
|
<div class="basket-message-container">
|
||||||
<div
|
<div
|
||||||
x-cloak
|
x-cloak
|
||||||
class="alert alert-red basket-error"
|
class="alert basket-message"
|
||||||
x-show="alertMessage.show"
|
:class="alertMessage.success ? 'alert-green' : 'alert-red'"
|
||||||
|
x-show="alertMessage.open"
|
||||||
x-transition.duration.500ms
|
x-transition.duration.500ms
|
||||||
x-text="alertMessage.content"
|
x-text="alertMessage.content"
|
||||||
></div>
|
></div>
|
||||||
@@ -111,9 +110,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<button @click.prevent="addToBasketWithMessage(item.product.id, -1)">-</button>
|
<button @click.prevent="addToBasket(item.product.id, -1)">-</button>
|
||||||
<span class="quantity" x-text="item.quantity"></span>
|
<span class="quantity" x-text="item.quantity"></span>
|
||||||
<button @click.prevent="addToBasketWithMessage(item.product.id, 1)">+</button>
|
<button @click.prevent="addToBasket(item.product.id, 1)">+</button>
|
||||||
|
|
||||||
<span x-text="item.product.name"></span> :
|
<span x-text="item.product.name"></span> :
|
||||||
<span x-text="item.sum().toLocaleString(undefined, { minimumFractionDigits: 2 })">€</span>
|
<span x-text="item.sum().toLocaleString(undefined, { minimumFractionDigits: 2 })">€</span>
|
||||||
@@ -213,7 +212,7 @@
|
|||||||
<h5 class="margin-bottom">{{ category }}</h5>
|
<h5 class="margin-bottom">{{ category }}</h5>
|
||||||
<div class="row gap-2x">
|
<div class="row gap-2x">
|
||||||
{% for product in categories[category] -%}
|
{% for product in categories[category] -%}
|
||||||
<button class="card shadow" @click="addToBasketWithMessage('{{ product.id }}', 1)">
|
<button class="card shadow" @click="addToBasket('{{ product.id }}', 1)">
|
||||||
<img
|
<img
|
||||||
class="card-image"
|
class="card-image"
|
||||||
alt="image de {{ product.name }}"
|
alt="image de {{ product.name }}"
|
||||||
@@ -252,6 +251,18 @@
|
|||||||
},
|
},
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
};
|
};
|
||||||
|
const formulas = [
|
||||||
|
{%- for formula in formulas -%}
|
||||||
|
{
|
||||||
|
result: {{ formula.result_id }},
|
||||||
|
products: [
|
||||||
|
{%- for product in formula.products.all() -%}
|
||||||
|
{{ product.id }},
|
||||||
|
{%- endfor -%}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{%- endfor -%}
|
||||||
|
];
|
||||||
const formInitial = [
|
const formInitial = [
|
||||||
{%- for f in form -%}
|
{%- for f in form -%}
|
||||||
{%- if f.cleaned_data -%}
|
{%- if f.cleaned_data -%}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
# OR WITHIN THE LOCAL FILE "LICENSE"
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
@@ -31,6 +32,7 @@ from counter.forms import BasketForm, RefillForm
|
|||||||
from counter.models import (
|
from counter.models import (
|
||||||
Counter,
|
Counter,
|
||||||
Customer,
|
Customer,
|
||||||
|
ProductFormula,
|
||||||
ReturnableProduct,
|
ReturnableProduct,
|
||||||
Selling,
|
Selling,
|
||||||
)
|
)
|
||||||
@@ -206,12 +208,13 @@ class CounterClick(
|
|||||||
"""Add customer to the context."""
|
"""Add customer to the context."""
|
||||||
kwargs = super().get_context_data(**kwargs)
|
kwargs = super().get_context_data(**kwargs)
|
||||||
kwargs["products"] = self.products
|
kwargs["products"] = self.products
|
||||||
kwargs["categories"] = {}
|
kwargs["formulas"] = ProductFormula.objects.filter(
|
||||||
|
result__in=self.products
|
||||||
|
).prefetch_related("products")
|
||||||
|
kwargs["categories"] = defaultdict(list)
|
||||||
for product in kwargs["products"]:
|
for product in kwargs["products"]:
|
||||||
if product.product_type:
|
if product.product_type:
|
||||||
kwargs["categories"].setdefault(product.product_type, []).append(
|
kwargs["categories"][product.product_type].append(product)
|
||||||
product
|
|
||||||
)
|
|
||||||
kwargs["customer"] = self.customer
|
kwargs["customer"] = self.customer
|
||||||
kwargs["cancel_url"] = self.get_success_url()
|
kwargs["cancel_url"] = self.get_success_url()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user