mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-10-15 10:04:59 +02:00
Compare commits
12 Commits
small_feat
...
26412bbd10
Author | SHA1 | Date | |
---|---|---|---|
|
26412bbd10 | ||
|
418268db27 | ||
|
73045586a3 | ||
|
d4cb464169 | ||
|
cb3b34f874 | ||
|
e6f3084588 | ||
|
145e55da75 | ||
|
d3ba95cdca | ||
|
8ffb0ebb56 | ||
|
5038af9e34 | ||
|
819b4214c9 | ||
|
b8a93b0b75 |
@@ -38,6 +38,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<input id="alias" type="text" class="form-control" placeholder="Nom/note ...">
|
<input id="alias" type="text" class="form-control" placeholder="Nom/note ...">
|
||||||
|
<button id="trigger" class="btn btn-secondary">Click me !</button>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
@@ -63,15 +64,46 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
refreshBalance();
|
refreshBalance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function process_qrcode() {
|
||||||
|
let name = alias_obj.val();
|
||||||
|
$.get("/api/note/note?search=" + name + "&format=json").done(
|
||||||
|
function (res) {
|
||||||
|
let note = res.results[0];
|
||||||
|
$.post("/api/activity/entry/?format=json", {
|
||||||
|
csrfmiddlewaretoken: CSRF_TOKEN,
|
||||||
|
activity: {{ activity.id }},
|
||||||
|
note: note.id,
|
||||||
|
guest: null
|
||||||
|
}).done(function () {
|
||||||
|
addMsg(interpolate(gettext(
|
||||||
|
"Entry made for %s whose balance is %s €"),
|
||||||
|
[note.name, note.balance / 100]), "success", 4000);
|
||||||
|
reloadTable(true);
|
||||||
|
}).fail(function (xhr) {
|
||||||
|
errMsg(xhr.responseJSON, 4000);
|
||||||
|
});
|
||||||
|
}).fail(function (xhr) {
|
||||||
|
errMsg(xhr.responseJSON, 4000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
alias_obj.keyup(function(event) {
|
alias_obj.keyup(function(event) {
|
||||||
let code = event.originalEvent.keyCode
|
let code = event.originalEvent.keyCode
|
||||||
if (65 <= code <= 122 || code === 13) {
|
if (65 <= code <= 122 || code === 13) {
|
||||||
debounce(reloadTable)()
|
debounce(reloadTable)()
|
||||||
}
|
}
|
||||||
|
if (code === 0)
|
||||||
|
process_qrcode();
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).ready(init);
|
$(document).ready(init);
|
||||||
|
|
||||||
|
alias_obj2 = document.getElementById("alias");
|
||||||
|
$("#trigger").click(function (e) {
|
||||||
|
addMsg("Clicked", "success", 1000);
|
||||||
|
alias_obj.val(alias_obj.val() + "\0");
|
||||||
|
alias_obj2.dispatchEvent(new KeyboardEvent('keyup'));
|
||||||
|
})
|
||||||
function init() {
|
function init() {
|
||||||
$(".table-row").click(function (e) {
|
$(".table-row").click(function (e) {
|
||||||
let target = e.target.parentElement;
|
let target = e.target.parentElement;
|
||||||
@@ -168,4 +200,4 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -74,15 +74,11 @@ class FoodListView(ProtectQuerysetMixin, LoginRequiredMixin, MultiTableMixin, Li
|
|||||||
|
|
||||||
search_table = qs.filter(PermissionBackend.filter_queryset(self.request, Food, 'view'))
|
search_table = qs.filter(PermissionBackend.filter_queryset(self.request, Food, 'view'))
|
||||||
# table open
|
# table open
|
||||||
open_table = self.get_queryset().filter(
|
open_table = self.get_queryset().order_by('expiry_date').filter(
|
||||||
Q(polymorphic_ctype__model='transformedfood')
|
Q(polymorphic_ctype__model='transformedfood')
|
||||||
| Q(polymorphic_ctype__model='basicfood', basicfood__date_type='DLC')).filter(
|
| Q(polymorphic_ctype__model='basicfood', basicfood__date_type='DLC')).filter(
|
||||||
expiry_date__lt=timezone.now(), end_of_life='').filter(
|
expiry_date__lt=timezone.now(), end_of_life='').filter(
|
||||||
PermissionBackend.filter_queryset(self.request, Food, 'view'))
|
PermissionBackend.filter_queryset(self.request, Food, 'view'))
|
||||||
open_table = open_table.union(self.get_queryset().filter(
|
|
||||||
Q(end_of_life='', order__iexact='open')
|
|
||||||
).filter(
|
|
||||||
PermissionBackend.filter_queryset(self.request, Food, 'view'))).order_by('expiry_date')
|
|
||||||
# table served
|
# table served
|
||||||
served_table = self.get_queryset().order_by('-pk').filter(
|
served_table = self.get_queryset().order_by('-pk').filter(
|
||||||
end_of_life='', is_ready=True).exclude(
|
end_of_life='', is_ready=True).exclude(
|
||||||
|
@@ -417,7 +417,7 @@ class Membership(models.Model):
|
|||||||
A membership is valid if today is between the start and the end date.
|
A membership is valid if today is between the start and the end date.
|
||||||
"""
|
"""
|
||||||
if self.date_end is not None:
|
if self.date_end is not None:
|
||||||
return self.date_start.toordinal() <= datetime.datetime.now().toordinal() <= self.date_end.toordinal()
|
return self.date_start.toordinal() <= datetime.datetime.now().toordinal() < self.date_end.toordinal()
|
||||||
else:
|
else:
|
||||||
return self.date_start.toordinal() <= datetime.datetime.now().toordinal()
|
return self.date_start.toordinal() <= datetime.datetime.now().toordinal()
|
||||||
|
|
||||||
|
@@ -73,7 +73,10 @@
|
|||||||
{% if user_object.pk == user.pk %}
|
{% if user_object.pk == user.pk %}
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<a class="small badge badge-secondary" href="{% url 'member:auth_token' %}">
|
<a class="small badge badge-secondary" href="{% url 'member:auth_token' %}">
|
||||||
<i class="fa fa-cogs"></i>{% trans 'API token' %}
|
<i class="fa fa-cogs"></i> {% trans 'API token' %}
|
||||||
|
</a>
|
||||||
|
<a class="small badge badge-secondary" href="{% url 'member:qr_code' user_object.pk %}">
|
||||||
|
<i class="fa fa-qrcode"></i> {% trans 'QR Code' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
36
apps/member/templates/member/qr_code.html
Normal file
36
apps/member/templates/member/qr_code.html
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% comment %}
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
{% endcomment %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="card bg-light">
|
||||||
|
<h3 class="card-header text-center">
|
||||||
|
{% trans "QR Code for" %} {{ user_object.username }} ({{ user_object.first_name }} {{user_object.last_name }})
|
||||||
|
</h3>
|
||||||
|
<div class="text-center" id="qrcode">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrajavascript %}
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js" integrity="sha512-CNgIRecGo7nphbeZ04Sc13ka07paqdeTu0WR1IM4kNcpmBAUSHSQX0FslNhTDadL4O5SAGapGt4FodqL8My0mA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
<script>
|
||||||
|
var qrc = new QRCode(document.getElementById("qrcode"), {
|
||||||
|
text: "{{ user_object.pk }}\0",
|
||||||
|
width: 1024,
|
||||||
|
height: 1024
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extracss %}
|
||||||
|
<style>
|
||||||
|
img {
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
@@ -25,4 +25,5 @@ urlpatterns = [
|
|||||||
path('user/<int:pk>/aliases/', views.ProfileAliasView.as_view(), name="user_alias"),
|
path('user/<int:pk>/aliases/', views.ProfileAliasView.as_view(), name="user_alias"),
|
||||||
path('user/<int:pk>/trust', views.ProfileTrustView.as_view(), name="user_trust"),
|
path('user/<int:pk>/trust', views.ProfileTrustView.as_view(), name="user_trust"),
|
||||||
path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'),
|
path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'),
|
||||||
|
path('user/<int:pk>/qr_code/', views.QRCodeView.as_view(), name='qr_code'),
|
||||||
]
|
]
|
||||||
|
@@ -408,6 +408,14 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
|
|||||||
context['token'] = Token.objects.get_or_create(user=self.request.user)[0]
|
context['token'] = Token.objects.get_or_create(user=self.request.user)[0]
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
class QRCodeView(LoginRequiredMixin, DetailView):
|
||||||
|
"""
|
||||||
|
Affiche le QR Code
|
||||||
|
"""
|
||||||
|
model = User
|
||||||
|
context_object_name = "user_object"
|
||||||
|
template_name = "member/qr_code.html"
|
||||||
|
extra_context = {"title": _("QR Code")}
|
||||||
|
|
||||||
# ******************************* #
|
# ******************************* #
|
||||||
# CLUB #
|
# CLUB #
|
||||||
|
@@ -228,7 +228,7 @@ function consume (source, source_alias, dest, quantity, amount, reason, type, ca
|
|||||||
addMsg(interpolate(gettext('Warning, the transaction from the note %s succeed, ' +
|
addMsg(interpolate(gettext('Warning, the transaction from the note %s succeed, ' +
|
||||||
'but the emitter note %s is negative.'), [source_alias, source_alias]), 'warning', 30000)
|
'but the emitter note %s is negative.'), [source_alias, source_alias]), 'warning', 30000)
|
||||||
}
|
}
|
||||||
if (source.membership && source.membership.date_end <= new Date().toISOString()) {
|
if (source.membership && source.membership.date_end < new Date().toISOString()) {
|
||||||
addMsg(interpolate(gettext('Warning, the emitter note %s is no more a BDE member.'), [source_alias]),
|
addMsg(interpolate(gettext('Warning, the emitter note %s is no more a BDE member.'), [source_alias]),
|
||||||
'danger', 30000)
|
'danger', 30000)
|
||||||
}
|
}
|
||||||
|
@@ -310,10 +310,10 @@ $('#btn_transfer').click(function () {
|
|||||||
destination: dest.note.id,
|
destination: dest.note.id,
|
||||||
destination_alias: dest.name
|
destination_alias: dest.name
|
||||||
}).done(function () {
|
}).done(function () {
|
||||||
if (source.note.membership && source.note.membership.date_end <= new Date().toISOString()) {
|
if (source.note.membership && source.note.membership.date_end < new Date().toISOString()) {
|
||||||
addMsg(interpolate(gettext('Warning, the emitter note %s is no more a BDE member.'), [source.name]), 'danger', 30000)
|
addMsg(interpolate(gettext('Warning, the emitter note %s is no more a BDE member.'), [source.name]), 'danger', 30000)
|
||||||
}
|
}
|
||||||
if (dest.note.membership && dest.note.membership.date_end <= new Date().toISOString()) {
|
if (dest.note.membership && dest.note.membership.date_end < new Date().toISOString()) {
|
||||||
addMsg(interpolate(gettext('Warning, the destination note %s is no more a BDE member.'), [dest.name]), 'danger', 30000)
|
addMsg(interpolate(gettext('Warning, the destination note %s is no more a BDE member.'), [dest.name]), 'danger', 30000)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +414,7 @@ $('#btn_transfer').click(function () {
|
|||||||
bank: $('#bank').val()
|
bank: $('#bank').val()
|
||||||
}).done(function () {
|
}).done(function () {
|
||||||
addMsg(gettext('Credit/debit succeed!'), 'success', 10000)
|
addMsg(gettext('Credit/debit succeed!'), 'success', 10000)
|
||||||
if (user_note.membership && user_note.membership.date_end <= new Date().toISOString()) { addMsg(gettext('Warning, the emitter note %s is no more a BDE member.'), 'danger', 10000) }
|
if (user_note.membership && user_note.membership.date_end < new Date().toISOString()) { addMsg(gettext('Warning, the emitter note %s is no more a BDE member.'), 'danger', 10000) }
|
||||||
reset()
|
reset()
|
||||||
}).fail(function (err) {
|
}).fail(function (err) {
|
||||||
const errObj = JSON.parse(err.responseText)
|
const errObj = JSON.parse(err.responseText)
|
||||||
|
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.2.6 on 2025-09-28 20:12
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('treasury', '0010_alter_invoice_bde'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='sogecredit',
|
|
||||||
name='valid',
|
|
||||||
field=models.BooleanField(blank=True, default=False, verbose_name='Valid'),
|
|
||||||
),
|
|
||||||
]
|
|
@@ -308,12 +308,6 @@ class SogeCredit(models.Model):
|
|||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
valid = models.BooleanField(
|
|
||||||
default=False,
|
|
||||||
verbose_name=_("Valid"),
|
|
||||||
blank=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Credit from the Société générale")
|
verbose_name = _("Credit from the Société générale")
|
||||||
verbose_name_plural = _("Credits from the Société générale")
|
verbose_name_plural = _("Credits from the Société générale")
|
||||||
@@ -344,7 +338,7 @@ class SogeCredit(models.Model):
|
|||||||
credit_transaction.save()
|
credit_transaction.save()
|
||||||
credit_transaction.refresh_from_db()
|
credit_transaction.refresh_from_db()
|
||||||
self.credit_transaction = credit_transaction
|
self.credit_transaction = credit_transaction
|
||||||
elif not self.valid_legacy:
|
elif not self.valid:
|
||||||
self.credit_transaction.amount = self.amount
|
self.credit_transaction.amount = self.amount
|
||||||
self.credit_transaction._force_save = True
|
self.credit_transaction._force_save = True
|
||||||
self.credit_transaction.save()
|
self.credit_transaction.save()
|
||||||
@@ -352,12 +346,12 @@ class SogeCredit(models.Model):
|
|||||||
return super().save(*args, **kwargs)
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def valid_legacy(self):
|
def valid(self):
|
||||||
return self.credit_transaction and self.credit_transaction.valid
|
return self.credit_transaction and self.credit_transaction.valid
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def amount(self):
|
def amount(self):
|
||||||
if self.valid_legacy:
|
if self.valid:
|
||||||
return self.credit_transaction.total
|
return self.credit_transaction.total
|
||||||
amount = 0
|
amount = 0
|
||||||
transactions_wei = self.transactions.filter(membership__club__weiclub__isnull=False)
|
transactions_wei = self.transactions.filter(membership__club__weiclub__isnull=False)
|
||||||
@@ -371,7 +365,7 @@ class SogeCredit(models.Model):
|
|||||||
The Sogé credit may be created after the user already paid its memberships.
|
The Sogé credit may be created after the user already paid its memberships.
|
||||||
We query transactions and update the credit, if it is unvalid.
|
We query transactions and update the credit, if it is unvalid.
|
||||||
"""
|
"""
|
||||||
if self.valid_legacy or not self.pk:
|
if self.valid or not self.pk:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Soge do not pay BDE and kfet memberships since 2022
|
# Soge do not pay BDE and kfet memberships since 2022
|
||||||
@@ -411,7 +405,7 @@ class SogeCredit(models.Model):
|
|||||||
Invalidating a Société générale delete the transaction of the bank if it was already created.
|
Invalidating a Société générale delete the transaction of the bank if it was already created.
|
||||||
Treasurers must know what they do, With Great Power Comes Great Responsibility...
|
Treasurers must know what they do, With Great Power Comes Great Responsibility...
|
||||||
"""
|
"""
|
||||||
if self.valid_legacy:
|
if self.valid:
|
||||||
self.credit_transaction.valid = False
|
self.credit_transaction.valid = False
|
||||||
self.credit_transaction.save()
|
self.credit_transaction.save()
|
||||||
for tr in self.transactions.all():
|
for tr in self.transactions.all():
|
||||||
@@ -420,7 +414,7 @@ class SogeCredit(models.Model):
|
|||||||
tr.save()
|
tr.save()
|
||||||
|
|
||||||
def validate(self, force=False):
|
def validate(self, force=False):
|
||||||
if self.valid_legacy and not force:
|
if self.valid and not force:
|
||||||
# The credit is already done
|
# The credit is already done
|
||||||
return
|
return
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 284 KiB After Width: | Height: | Size: 104 KiB |
@@ -12,7 +12,7 @@ django-filter~=25.1
|
|||||||
django-mailer~=2.3.2
|
django-mailer~=2.3.2
|
||||||
django-oauth-toolkit~=3.0.1
|
django-oauth-toolkit~=3.0.1
|
||||||
django-phonenumber-field~=8.1.0
|
django-phonenumber-field~=8.1.0
|
||||||
django-polymorphic~=4.1.0
|
django-polymorphic~=3.1.0
|
||||||
djangorestframework~=3.16.0
|
djangorestframework~=3.16.0
|
||||||
django-rest-polymorphic~=0.1.10
|
django-rest-polymorphic~=0.1.10
|
||||||
django-tables2~=2.7.5
|
django-tables2~=2.7.5
|
||||||
|
Reference in New Issue
Block a user