mirror of
https://github.com/ae-utbm/sith.git
synced 2026-02-21 05:18:38 +00:00
Compare commits
7 Commits
dependabot
...
taiste
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71ed7cdf7d | ||
|
|
43768171a1 | ||
|
|
0eccb4a5b5 | ||
|
|
e7584c8c83 | ||
|
|
ac06de4f55 | ||
|
|
e2fca3e6d2 | ||
|
|
2138783bde |
@@ -35,7 +35,7 @@ TODO : rewrite the pagination used in this template an Alpine one
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form }}
|
{{ form }}
|
||||||
<p><input type="submit" value="{% trans %}Show{% endtrans %}" /></p>
|
<p><input type="submit" value="{% trans %}Show{% endtrans %}" /></p>
|
||||||
<p><input type="submit" value="{% trans %}Download as cvs{% endtrans %}" formaction="{{ url('club:sellings_csv', club_id=object.id) }}"/></p>
|
<p><input type="submit" value="{% trans %}Download as CSV{% endtrans %}" formaction="{{ url('club:sellings_csv', club_id=object.id) }}"/></p>
|
||||||
</form>
|
</form>
|
||||||
<p>
|
<p>
|
||||||
{% trans %}Quantity: {% endtrans %}{{ total_quantity }} {% trans %}units{% endtrans %}<br/>
|
{% trans %}Quantity: {% endtrans %}{{ total_quantity }} {% trans %}units{% endtrans %}<br/>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from django.utils.timezone import localdate, make_aware, now
|
|||||||
from faker import Faker
|
from faker import Faker
|
||||||
|
|
||||||
from club.models import Club, Membership
|
from club.models import Club, Membership
|
||||||
from core.models import Group, User
|
from core.models import Group, User, UserBan
|
||||||
from counter.models import (
|
from counter.models import (
|
||||||
Counter,
|
Counter,
|
||||||
Customer,
|
Customer,
|
||||||
@@ -40,6 +40,7 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
self.stdout.write("Creating users...")
|
self.stdout.write("Creating users...")
|
||||||
users = self.create_users()
|
users = self.create_users()
|
||||||
|
self.create_bans(random.sample(users, k=len(users) // 200)) # 0.5% of users
|
||||||
subscribers = random.sample(users, k=int(0.8 * len(users)))
|
subscribers = random.sample(users, k=int(0.8 * len(users)))
|
||||||
self.stdout.write("Creating subscriptions...")
|
self.stdout.write("Creating subscriptions...")
|
||||||
self.create_subscriptions(subscribers)
|
self.create_subscriptions(subscribers)
|
||||||
@@ -88,6 +89,8 @@ class Command(BaseCommand):
|
|||||||
self.stdout.write("Done")
|
self.stdout.write("Done")
|
||||||
|
|
||||||
def create_users(self) -> list[User]:
|
def create_users(self) -> list[User]:
|
||||||
|
# Create a single password hash for all users to make it faster.
|
||||||
|
# It's insecure as hell, but it's ok since it's only for dev purposes.
|
||||||
password = make_password("plop")
|
password = make_password("plop")
|
||||||
users = [
|
users = [
|
||||||
User(
|
User(
|
||||||
@@ -114,14 +117,33 @@ class Command(BaseCommand):
|
|||||||
public_group.users.add(*users)
|
public_group.users.add(*users)
|
||||||
return users
|
return users
|
||||||
|
|
||||||
|
def create_bans(self, users: list[User]):
|
||||||
|
ban_groups = [
|
||||||
|
settings.SITH_GROUP_BANNED_COUNTER_ID,
|
||||||
|
settings.SITH_GROUP_BANNED_SUBSCRIPTION_ID,
|
||||||
|
settings.SITH_GROUP_BANNED_ALCOHOL_ID,
|
||||||
|
]
|
||||||
|
UserBan.objects.bulk_create(
|
||||||
|
[
|
||||||
|
UserBan(
|
||||||
|
user=user,
|
||||||
|
ban_group_id=i,
|
||||||
|
reason=self.faker.sentence(),
|
||||||
|
expires_at=make_aware(self.faker.future_datetime("+1y")),
|
||||||
|
)
|
||||||
|
for user in users
|
||||||
|
for i in random.sample(ban_groups, k=random.randint(1, len(ban_groups)))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
def create_subscriptions(self, users: list[User]):
|
def create_subscriptions(self, users: list[User]):
|
||||||
def prepare_subscription(_user: User, start_date: date) -> Subscription:
|
def prepare_subscription(_user: User, start_date: date) -> Subscription:
|
||||||
payment_method = random.choice(settings.SITH_SUBSCRIPTION_PAYMENT_METHOD)[0]
|
payment_method = random.choice(settings.SITH_SUBSCRIPTION_PAYMENT_METHOD)[0]
|
||||||
duration = random.randint(1, 4)
|
duration = random.randint(1, 4)
|
||||||
sub = Subscription(member=_user, payment_method=payment_method)
|
s = Subscription(member=_user, payment_method=payment_method)
|
||||||
sub.subscription_start = sub.compute_start(d=start_date, duration=duration)
|
s.subscription_start = s.compute_start(d=start_date, duration=duration)
|
||||||
sub.subscription_end = sub.compute_end(duration)
|
s.subscription_end = s.compute_end(duration)
|
||||||
return sub
|
return s
|
||||||
|
|
||||||
subscriptions = []
|
subscriptions = []
|
||||||
customers = []
|
customers = []
|
||||||
|
|||||||
@@ -39,8 +39,9 @@ class ProductAdmin(SearchModelAdmin):
|
|||||||
"code",
|
"code",
|
||||||
"product_type",
|
"product_type",
|
||||||
"selling_price",
|
"selling_price",
|
||||||
"profit",
|
|
||||||
"archived",
|
"archived",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
)
|
)
|
||||||
list_select_related = ("product_type",)
|
list_select_related = ("product_type",)
|
||||||
search_fields = ("name", "code")
|
search_fields = ("name", "code")
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# Generated by Django 5.2.8 on 2026-02-10 15:40
|
||||||
|
from operator import attrgetter
|
||||||
|
|
||||||
|
import django.utils.timezone
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.db.migrations.state import StateApps
|
||||||
|
from django.db.models import OuterRef, Subquery
|
||||||
|
|
||||||
|
from counter.models import Selling
|
||||||
|
|
||||||
|
|
||||||
|
def apply_product_history_dates(apps: StateApps, schema_editor):
|
||||||
|
"""Approximate a posteriori the value of created_at and updated_at."""
|
||||||
|
Product = apps.get_model("counter", "Product")
|
||||||
|
sales_subquery = Selling.objects.filter(product=OuterRef("pk")).values("date")
|
||||||
|
|
||||||
|
# for products that have an associated sale, we set the creation date
|
||||||
|
# to the one of the first sale, and the update date to the one of the last sale
|
||||||
|
products = list(
|
||||||
|
Product.objects.exclude(sellings=None)
|
||||||
|
.annotate(
|
||||||
|
new_created_at=Subquery(sales_subquery.order_by("date")[:1]),
|
||||||
|
new_updated_at=Subquery(sales_subquery.order_by("-date")[:1]),
|
||||||
|
)
|
||||||
|
.only("id")
|
||||||
|
)
|
||||||
|
for product in products:
|
||||||
|
product.created_at = product.new_created_at
|
||||||
|
product.updated_at = product.new_updated_at
|
||||||
|
|
||||||
|
# For the remaining products (those without sale),
|
||||||
|
# they are given the creation and update date of the previous product having sales.
|
||||||
|
products_without_sale = list(Product.objects.filter(sellings=None).only("id"))
|
||||||
|
for product in products_without_sale:
|
||||||
|
previous_product = max(
|
||||||
|
(p for p in products if p.id < product.id), key=attrgetter("id")
|
||||||
|
)
|
||||||
|
product.created_at = previous_product.created_at
|
||||||
|
product.updated_at = previous_product.updated_at
|
||||||
|
products.extend(products_without_sale)
|
||||||
|
|
||||||
|
Product.objects.bulk_update(products, fields=["created_at", "updated_at"])
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [("counter", "0035_remove_selling_is_validated_and_more")]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="product",
|
||||||
|
name="created_at",
|
||||||
|
field=models.DateTimeField(
|
||||||
|
auto_now_add=True,
|
||||||
|
default=django.utils.timezone.now,
|
||||||
|
verbose_name="created at",
|
||||||
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="product",
|
||||||
|
name="updated_at",
|
||||||
|
field=models.DateTimeField(auto_now=True, verbose_name="updated at"),
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
apply_product_history_dates, reverse_code=migrations.RunPython.noop
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -399,6 +399,8 @@ class Product(models.Model):
|
|||||||
Group, related_name="products", verbose_name=_("buying groups"), blank=True
|
Group, related_name="products", verbose_name=_("buying groups"), blank=True
|
||||||
)
|
)
|
||||||
archived = models.BooleanField(_("archived"), default=False)
|
archived = models.BooleanField(_("archived"), default=False)
|
||||||
|
created_at = models.DateTimeField(_("created at"), auto_now_add=True)
|
||||||
|
updated_at = models.DateTimeField(_("updated at"), auto_now=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("product")
|
verbose_name = _("product")
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
{% if object %}
|
{% if object %}
|
||||||
<h2>{% trans name=object %}Edit product {{ name }}{% endtrans %}</h2>
|
<h2>{% trans name=object %}Edit product {{ name }}{% endtrans %}</h2>
|
||||||
|
<p><i>{% trans %}Creation date{% endtrans %} : {{ object.created_at|date }}</i></p>
|
||||||
|
<p><i>{% trans %}Last update{% endtrans %} : {{ object.updated_at|date }}</i></p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<h2>{% trans %}Product creation{% endtrans %}</h2>
|
<h2>{% trans %}Product creation{% endtrans %}</h2>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
:disabled="csvLoading"
|
:disabled="csvLoading"
|
||||||
:aria-busy="csvLoading"
|
:aria-busy="csvLoading"
|
||||||
>
|
>
|
||||||
{% trans %}Download as cvs{% endtrans %} <i class="fa fa-file-arrow-down"></i>
|
{% trans %}Download as CSV{% endtrans %} <i class="fa fa-file-arrow-down"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-02-08 16:14+0100\n"
|
"POT-Creation-Date: 2026-02-14 15:21+0100\n"
|
||||||
"PO-Revision-Date: 2016-07-18\n"
|
"PO-Revision-Date: 2016-07-18\n"
|
||||||
"Last-Translator: Maréchal <thomas.girod@utbm.fr\n"
|
"Last-Translator: Maréchal <thomas.girod@utbm.fr\n"
|
||||||
"Language-Team: AE info <ae.info@utbm.fr>\n"
|
"Language-Team: AE info <ae.info@utbm.fr>\n"
|
||||||
@@ -388,7 +388,7 @@ msgstr "Montrer"
|
|||||||
|
|
||||||
#: club/templates/club/club_sellings.jinja
|
#: club/templates/club/club_sellings.jinja
|
||||||
#: counter/templates/counter/product_list.jinja
|
#: counter/templates/counter/product_list.jinja
|
||||||
msgid "Download as cvs"
|
msgid "Download as CSV"
|
||||||
msgstr "Télécharger en CSV"
|
msgstr "Télécharger en CSV"
|
||||||
|
|
||||||
#: club/templates/club/club_sellings.jinja
|
#: club/templates/club/club_sellings.jinja
|
||||||
@@ -1566,7 +1566,7 @@ msgstr "Visiteur"
|
|||||||
msgid "ban type"
|
msgid "ban type"
|
||||||
msgstr "type de ban"
|
msgstr "type de ban"
|
||||||
|
|
||||||
#: core/models.py
|
#: core/models.py counter/models.py
|
||||||
msgid "created at"
|
msgid "created at"
|
||||||
msgstr "créé le"
|
msgstr "créé le"
|
||||||
|
|
||||||
@@ -3109,6 +3109,10 @@ msgstr "groupe d'achat"
|
|||||||
msgid "archived"
|
msgid "archived"
|
||||||
msgstr "archivé"
|
msgstr "archivé"
|
||||||
|
|
||||||
|
#: counter/models.py
|
||||||
|
msgid "updated at"
|
||||||
|
msgstr "mis à jour le"
|
||||||
|
|
||||||
#: counter/models.py
|
#: counter/models.py
|
||||||
msgid "product"
|
msgid "product"
|
||||||
msgstr "produit"
|
msgstr "produit"
|
||||||
@@ -3664,6 +3668,14 @@ msgstr ""
|
|||||||
msgid "Edit product %(name)s"
|
msgid "Edit product %(name)s"
|
||||||
msgstr "Édition du produit %(name)s"
|
msgstr "Édition du produit %(name)s"
|
||||||
|
|
||||||
|
#: counter/templates/counter/product_form.jinja
|
||||||
|
msgid "Creation date"
|
||||||
|
msgstr "Date de création"
|
||||||
|
|
||||||
|
#: counter/templates/counter/product_form.jinja
|
||||||
|
msgid "Last update"
|
||||||
|
msgstr "Dernière mise à jour"
|
||||||
|
|
||||||
#: counter/templates/counter/product_form.jinja
|
#: counter/templates/counter/product_form.jinja
|
||||||
msgid "Product creation"
|
msgid "Product creation"
|
||||||
msgstr "Création de produit"
|
msgstr "Création de produit"
|
||||||
@@ -3951,8 +3963,8 @@ msgid ""
|
|||||||
"inconvenience."
|
"inconvenience."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Les paiements par carte bancaire sont actuellement désactivés sur l'eboutic. "
|
"Les paiements par carte bancaire sont actuellement désactivés sur l'eboutic. "
|
||||||
"Vous pouvez cependant toujours recharger votre compte dans un des lieux de vie de l'AE. "
|
"Vous pouvez cependant toujours recharger votre compte dans un des lieux de "
|
||||||
"Veuillez nous excuser pour le désagrément."
|
"vie de l'AE. Veuillez nous excuser pour le désagrément."
|
||||||
|
|
||||||
#: eboutic/templates/eboutic/eboutic_checkout.jinja
|
#: eboutic/templates/eboutic/eboutic_checkout.jinja
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -4121,8 +4133,8 @@ msgstr "Les candidatures sont fermées pour cette élection"
|
|||||||
#: election/templates/election/election_detail.jinja
|
#: election/templates/election/election_detail.jinja
|
||||||
msgid "Candidate pictures won't display for privacy reasons."
|
msgid "Candidate pictures won't display for privacy reasons."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"La photo du candidat ne s'affiche pas pour "
|
"La photo du candidat ne s'affiche pas pour des raisons de respect de la vie "
|
||||||
"des raisons de respect de la vie privée."
|
"privée."
|
||||||
|
|
||||||
#: election/templates/election/election_detail.jinja
|
#: election/templates/election/election_detail.jinja
|
||||||
msgid "Polls close "
|
msgid "Polls close "
|
||||||
|
|||||||
8
uv.lock
generated
8
uv.lock
generated
@@ -2362,11 +2362,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.6.3"
|
version = "2.5.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
|
{ url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2446,4 +2446,4 @@ dependencies = [
|
|||||||
{ name = "django-haystack" },
|
{ name = "django-haystack" },
|
||||||
{ name = "filelock" },
|
{ name = "filelock" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/a3/db/c6219763f6c4519cdaae812e60fd9471a7805de2b39d912931e45575c8e6/xapian-haystack-3.1.0.tar.gz", hash = "sha256:9f9ab90bf450bf6699d164594d569243aafb6c9f0990a16855f55a1d16bc09c6", size = 37887, upload-time = "2023-03-19T11:58:37.035Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/a3/db/c6219763f6c4519cdaae812e60fd9471a7805de2b39d912931e45575c8e6/xapian-haystack-3.1.0.tar.gz", hash = "sha256:9f9ab90bf450bf6699d164594d569243aafb6c9f0990a16855f55a1d16bc09c6", size = 37887, upload-time = "2023-03-19T11:58:37.035Z" }
|
||||||
Reference in New Issue
Block a user