Compare commits

...

7 Commits

Author SHA1 Message Date
Yohann D'ANELLO 11fbbca2a8 Amount help text in transaction templates forms can be misleading: they type euros not cents 2020-08-09 14:52:57 +02:00
Yohann D'ANELLO 901af1a86a Use var instead of let to declare a global var (turbolinks...) 2020-08-09 14:01:59 +02:00
Yohann D'ANELLO 5f87e76be8 Fix Profile model in Django Admin 2020-08-09 13:42:37 +02:00
Yohann D'ANELLO 8c885d372b Typo, closes #57 2020-08-09 13:23:22 +02:00
Yohann D'ANELLO 255e4dd0aa Lock interfaces when a transfer is performed to prevent spam click accidents 2020-08-09 13:19:27 +02:00
Yohann D'ANELLO 4afb849aec I hate you JS 2020-08-09 12:42:25 +02:00
Yohann D'ANELLO 872456df20 🐛 Don't break the note 2020-08-09 12:31:06 +02:00
8 changed files with 72 additions and 31 deletions

View File

@ -142,7 +142,10 @@ class Profile(models.Model):
indexes = [models.Index(fields=['user'])] indexes = [models.Index(fields=['user'])]
def get_absolute_url(self): def get_absolute_url(self):
return reverse('user_detail', args=(self.pk,)) return reverse('member:user_detail', args=(self.user_id,))
def __str__(self):
return str(self.user)
def send_email_validation_link(self): def send_email_validation_link(self):
subject = "[Note Kfet]" + str(_("Activate your Note Kfet account")) subject = "[Note Kfet]" + str(_("Activate your Note Kfet account"))

View File

@ -237,9 +237,9 @@ class TransactionPolymorphicSerializer(PolymorphicSerializer):
field.set(value) field.set(value)
else: else:
setattr(instance, attr, value) setattr(instance, attr, value)
instance.validate(True) instance.validate()
else: else:
serializer.Meta.model(**attrs).validate(True) serializer.Meta.model(**attrs).validate()
attrs[self.resource_type_field_name] = resource_type attrs[self.resource_type_field_name] = resource_type
return super().validate(attrs) return super().validate(attrs)

View File

@ -57,7 +57,6 @@ class TransactionTemplate(models.Model):
amount = models.PositiveIntegerField( amount = models.PositiveIntegerField(
verbose_name=_('amount'), verbose_name=_('amount'),
help_text=_('in centimes'),
) )
category = models.ForeignKey( category = models.ForeignKey(
TemplateCategory, TemplateCategory,
@ -164,7 +163,7 @@ class Transaction(PolymorphicModel):
models.Index(fields=['destination']), models.Index(fields=['destination']),
] ]
def validate(self, reset=False): def validate(self):
previous_source_balance = self.source.balance previous_source_balance = self.source.balance
previous_dest_balance = self.destination.balance previous_dest_balance = self.destination.balance
@ -188,23 +187,19 @@ class Transaction(PolymorphicModel):
source_balance = self.source.balance source_balance = self.source.balance
dest_balance = self.destination.balance dest_balance = self.destination.balance
if reset:
self.source.balance = previous_source_balance
self.destination.balance = previous_dest_balance
if source_balance > 2147483647 or source_balance < -2147483648\ if source_balance > 2147483647 or source_balance < -2147483648\
or dest_balance > 2147483647 or dest_balance < -2147483648: or dest_balance > 2147483647 or dest_balance < -2147483648:
raise ValidationError(_("The note balances must be between - 21 474 836.47 € and 21 474 836.47 €.")) raise ValidationError(_("The note balances must be between - 21 474 836.47 € and 21 474 836.47 €."))
return source_balance - previous_source_balance, dest_balance - previous_dest_balance
@transaction.atomic @transaction.atomic
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
""" """
When saving, also transfer money between two notes When saving, also transfer money between two notes
""" """
with transaction.atomic(): with transaction.atomic():
self.source.refresh_from_db() diff_source, diff_dest = self.validate()
self.destination.refresh_from_db()
self.validate(False)
if not self.source.is_active or not self.destination.is_active: if not self.source.is_active or not self.destination.is_active:
if 'force_insert' not in kwargs or not kwargs['force_insert']: if 'force_insert' not in kwargs or not kwargs['force_insert']:
@ -229,9 +224,13 @@ class Transaction(PolymorphicModel):
self.log("Saved") self.log("Saved")
# Save notes # Save notes
self.source.refresh_from_db()
self.source.balance += diff_source
self.source._force_save = True self.source._force_save = True
self.source.save() self.source.save()
self.log("Source saved") self.log("Source saved")
self.destination.refresh_from_db()
self.destination.balance += diff_dest
self.destination._force_save = True self.destination._force_save = True
self.destination.save() self.destination.save()
self.log("Destination saved") self.log("Destination saved")

View File

@ -847,10 +847,6 @@ msgstr ""
msgid "A template with this name already exist" msgid "A template with this name already exist"
msgstr "" msgstr ""
#: apps/note/models/transactions.py:60
msgid "in centimes"
msgstr ""
#: apps/note/models/transactions.py:72 #: apps/note/models/transactions.py:72
msgid "display" msgid "display"
msgstr "" msgstr ""

View File

@ -504,7 +504,7 @@ msgstr "adresse email confirmée"
#: apps/member/models.py:111 #: apps/member/models.py:111
msgid "registration valid" msgid "registration valid"
msgstr "inscription valid" msgstr "inscription valide"
#: apps/member/models.py:140 apps/member/models.py:141 #: apps/member/models.py:140 apps/member/models.py:141
msgid "user profile" msgid "user profile"
@ -854,10 +854,6 @@ msgstr "catégories de transaction"
msgid "A template with this name already exist" msgid "A template with this name already exist"
msgstr "Un modèle de transaction avec un nom similaire existe déjà." msgstr "Un modèle de transaction avec un nom similaire existe déjà."
#: apps/note/models/transactions.py:60
msgid "in centimes"
msgstr "en centimes"
#: apps/note/models/transactions.py:72 #: apps/note/models/transactions.py:72
msgid "display" msgid "display"
msgstr "afficher" msgstr "afficher"
@ -2373,7 +2369,7 @@ msgid ""
"You recently registered on the Note Kfet. Please click on the link below to " "You recently registered on the Note Kfet. Please click on the link below to "
"confirm your registration." "confirm your registration."
msgstr "" msgstr ""
"Vous vous êtes inscrits récemment sur la Note Kfet. Merci de cliquer sur le " "Vous vous êtes inscrit·e récemment sur la Note Kfet. Merci de cliquer sur le "
"lien ci-dessous pour confirmer votre adresse email." "lien ci-dessous pour confirmer votre adresse email."
#: templates/registration/mails/email_validation_email.html:26 #: templates/registration/mails/email_validation_email.html:26

View File

@ -265,7 +265,10 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr
consumers.results.forEach(function (consumer) { consumers.results.forEach(function (consumer) {
let note = consumer.note; let note = consumer.note;
note.email_confirmed = consumer.email_confirmed; note.email_confirmed = consumer.email_confirmed;
note.membership = consumer.membership; if (consumer.hasOwnProperty("membership") && consumer.membership)
note.membership = consumer.membership;
else
note.membership = undefined;
let extra_css = displayStyle(note); let extra_css = displayStyle(note);
aliases_matched_html += li(alias_prefix + '_' + consumer.id, aliases_matched_html += li(alias_prefix + '_' + consumer.id,
consumer.name, consumer.name,

View File

@ -1,6 +1,9 @@
// Copyright (C) 2018-2020 by BDE ENS Paris-Saclay // Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// When a transaction is performed, lock the interface to prevent spam clicks.
var LOCK = false;
/** /**
* Refresh the history table on the consumptions page. * Refresh the history table on the consumptions page.
*/ */
@ -35,8 +38,11 @@ $(document).ready(function() {
note_list_obj.html(""); note_list_obj.html("");
buttons.forEach(function(button) { buttons.forEach(function(button) {
$("#conso_button_" + button.id).click(removeNote(button, "conso_button", buttons, $("#conso_button_" + button.id).click(function() {
"consos_list")); if (LOCK)
return;
removeNote(button, "conso_button", buttons,"consos_list");
});
}); });
} }
}); });
@ -52,8 +58,11 @@ $(document).ready(function() {
$("#note_list").html(consos_list_obj.html()); $("#note_list").html(consos_list_obj.html());
consos_list_obj.html(""); consos_list_obj.html("");
buttons.forEach(function(button) { buttons.forEach(function(button) {
$("#conso_button_" + button.id).click(removeNote(button, "conso_button", buttons, $("#conso_button_" + button.id).click(function() {
"note_list")); if (LOCK)
return;
removeNote(button, "conso_button", buttons,"note_list");
});
}); });
} }
else { else {
@ -127,7 +136,11 @@ function addConso(dest, amount, type, category_id, category_name, template_id, t
$("#" + list).html(html); $("#" + list).html(html);
buttons.forEach(function(button) { buttons.forEach(function(button) {
$("#conso_button_" + button.id).click(removeNote(button, "conso_button", buttons, list)); $("#conso_button_" + button.id).click(function() {
if (LOCK)
return;
removeNote(button, "conso_button", buttons, list);
});
}); });
} }
else else
@ -148,6 +161,7 @@ function reset() {
$("#profile_pic_link").attr("href", "#"); $("#profile_pic_link").attr("href", "#");
refreshHistory(); refreshHistory();
refreshBalance(); refreshBalance();
LOCK = false;
} }
@ -155,6 +169,11 @@ function reset() {
* Apply all transactions: all notes in `notes` buy each item in `buttons` * Apply all transactions: all notes in `notes` buy each item in `buttons`
*/ */
function consumeAll() { function consumeAll() {
if (LOCK)
return;
LOCK = true;
let error = false; let error = false;
if (notes_display.length === 0) { if (notes_display.length === 0) {
@ -168,8 +187,10 @@ function consumeAll() {
error = true; error = true;
} }
if (error) if (error) {
LOCK = false;
return; return;
}
notes_display.forEach(function(note_display) { notes_display.forEach(function(note_display) {
buttons.forEach(function(button) { buttons.forEach(function(button) {
@ -218,7 +239,7 @@ function consume(source, source_alias, dest, quantity, amount, reason, type, cat
addMsg("Attention, La transaction depuis la note " + source_alias + " a été réalisée avec " + addMsg("Attention, La transaction depuis la note " + source_alias + " a été réalisée avec " +
"succès, mais la note émettrice " + source_alias + " est en négatif.", "succès, mais la note émettrice " + source_alias + " est en négatif.",
"warning", 30000); "warning", 30000);
if (source.note.membership && source.note.membership.date_end < new Date().toISOString()) if (source.membership && source.membership.date_end < new Date().toISOString())
addMsg("Attention : la note émettrice " + source.name + " n'est plus adhérente.", addMsg("Attention : la note émettrice " + source.name + " n'est plus adhérente.",
"danger", 30000); "danger", 30000);
} }

View File

@ -1,3 +1,5 @@
var LOCK = false;
sources = []; sources = [];
sources_notes_display = []; sources_notes_display = [];
dests = []; dests = [];
@ -42,6 +44,8 @@ function reset(refresh=true) {
refreshBalance(); refreshBalance();
refreshHistory(); refreshHistory();
} }
LOCK = false;
} }
$(document).ready(function() { $(document).ready(function() {
@ -91,6 +95,9 @@ $(document).ready(function() {
let dest = $("#dest_note"); let dest = $("#dest_note");
$("#type_transfer").click(function() { $("#type_transfer").click(function() {
if (LOCK)
return;
$("#source_me_div").removeClass('d-none'); $("#source_me_div").removeClass('d-none');
$("#source_note").removeClass('is-invalid'); $("#source_note").removeClass('is-invalid');
$("#dest_note").removeClass('is-invalid'); $("#dest_note").removeClass('is-invalid');
@ -102,6 +109,9 @@ $(document).ready(function() {
}); });
$("#type_credit").click(function() { $("#type_credit").click(function() {
if (LOCK)
return;
$("#source_me_div").addClass('d-none'); $("#source_me_div").addClass('d-none');
$("#source_note").removeClass('is-invalid'); $("#source_note").removeClass('is-invalid');
$("#dest_note").removeClass('is-invalid'); $("#dest_note").removeClass('is-invalid');
@ -122,6 +132,9 @@ $(document).ready(function() {
}); });
$("#type_debit").click(function() { $("#type_debit").click(function() {
if (LOCK)
return;
$("#source_me_div").addClass('d-none'); $("#source_me_div").addClass('d-none');
$("#source_note").removeClass('is-invalid'); $("#source_note").removeClass('is-invalid');
$("#dest_note").removeClass('is-invalid'); $("#dest_note").removeClass('is-invalid');
@ -165,6 +178,9 @@ $(document).ready(function() {
location.hash = ""; location.hash = "";
$("#source_me").click(function() { $("#source_me").click(function() {
if (LOCK)
return;
// Shortcut to set the current user as the only emitter // Shortcut to set the current user as the only emitter
sources_notes_display.length = 0; sources_notes_display.length = 0;
sources.length = 0; sources.length = 0;
@ -198,6 +214,11 @@ $(document).ready(function() {
}); });
$("#btn_transfer").click(function() { $("#btn_transfer").click(function() {
if (LOCK)
return;
LOCK = true;
let error = false; let error = false;
let amount_field = $("#amount"); let amount_field = $("#amount");
@ -237,8 +258,10 @@ $("#btn_transfer").click(function() {
error = true; error = true;
} }
if (error) if (error) {
LOCK = false;
return; return;
}
let reason = reason_field.val(); let reason = reason_field.val();