Format JS files

This commit is contained in:
Alexandre Iooss 2020-09-05 08:30:41 +02:00
parent a97a36bc9e
commit bad5fe3c22
No known key found for this signature in database
GPG Key ID: 6C79278F3FCDCC02
7 changed files with 1175 additions and 1229 deletions

View File

@ -3,21 +3,21 @@
*/ */
function create_alias (e) { function create_alias (e) {
// Do not submit HTML form // Do not submit HTML form
e.preventDefault(); e.preventDefault()
// Get data and send to API // Get data and send to API
const formData = new FormData(e.target); const formData = new FormData(e.target)
$.post("/api/note/alias/", { $.post('/api/note/alias/', {
"csrfmiddlewaretoken": formData.get("csrfmiddlewaretoken"), csrfmiddlewaretoken: formData.get('csrfmiddlewaretoken'),
"name": formData.get("name"), name: formData.get('name'),
"note": formData.get("note") note: formData.get('note')
}).done(function () { }).done(function () {
// Reload table // Reload table
$("#alias_table").load(location.pathname + " #alias_table"); $('#alias_table').load(location.pathname + ' #alias_table')
addMsg("Alias ajouté", "success"); addMsg('Alias ajouté', 'success')
}).fail(function (xhr, _textStatus, _error) { }).fail(function (xhr, _textStatus, _error) {
errMsg(xhr.responseJSON); errMsg(xhr.responseJSON)
}); })
} }
/** /**
@ -26,18 +26,18 @@ function create_alias (e) {
*/ */
function delete_button (button_id) { function delete_button (button_id) {
$.ajax({ $.ajax({
url: "/api/note/alias/" + button_id + "/", url: '/api/note/alias/' + button_id + '/',
method: "DELETE", method: 'DELETE',
headers: { "X-CSRFTOKEN": CSRF_TOKEN } headers: { 'X-CSRFTOKEN': CSRF_TOKEN }
}).done(function () { }).done(function () {
addMsg('Alias supprimé', 'success'); addMsg('Alias supprimé', 'success')
$("#alias_table").load(location.pathname + " #alias_table"); $('#alias_table').load(location.pathname + ' #alias_table')
}).fail(function (xhr, _textStatus, _error) { }).fail(function (xhr, _textStatus, _error) {
errMsg(xhr.responseJSON); errMsg(xhr.responseJSON)
}); })
} }
$(document).ready(function () { $(document).ready(function () {
// Attach event // Attach event
document.getElementById("form_alias").addEventListener("submit", create_alias); document.getElementById('form_alias').addEventListener('submit', create_alias)
}) })

View File

@ -1,57 +1,53 @@
$(document).ready(function () { $(document).ready(function () {
$(".autocomplete").keyup(function(e) { $('.autocomplete').keyup(function (e) {
let target = $("#" + e.target.id); const target = $('#' + e.target.id)
let prefix = target.attr("id"); const prefix = target.attr('id')
let api_url = target.attr("api_url"); const api_url = target.attr('api_url')
let api_url_suffix = target.attr("api_url_suffix"); let api_url_suffix = target.attr('api_url_suffix')
if (!api_url_suffix) if (!api_url_suffix) { api_url_suffix = '' }
api_url_suffix = ""; let name_field = target.attr('name_field')
let name_field = target.attr("name_field"); if (!name_field) { name_field = 'name' }
if (!name_field) const input = target.val()
name_field = "name"; target.addClass('is-invalid')
let input = target.val(); target.removeClass('is-valid')
target.addClass("is-invalid"); $('#' + prefix + '_reset').removeClass('d-none')
target.removeClass("is-valid");
$("#" + prefix + "_reset").removeClass("d-none");
$.getJSON(api_url + (api_url.includes("?") ? "&" : "?") + "format=json&search=^" + input + api_url_suffix, function(objects) { $.getJSON(api_url + (api_url.includes('?') ? '&' : '?') + 'format=json&search=^' + input + api_url_suffix, function (objects) {
let html = ""; let html = ''
objects.results.forEach(function (obj) { objects.results.forEach(function (obj) {
html += li(prefix + "_" + obj.id, obj[name_field]); html += li(prefix + '_' + obj.id, obj[name_field])
}); })
let results_list = $("#" + prefix + "_list"); const results_list = $('#' + prefix + '_list')
results_list.html(html); results_list.html(html)
objects.results.forEach(function (obj) { objects.results.forEach(function (obj) {
$("#" + prefix + "_" + obj.id).click(function() { $('#' + prefix + '_' + obj.id).click(function () {
target.val(obj[name_field]); target.val(obj[name_field])
$("#" + prefix + "_pk").val(obj.id); $('#' + prefix + '_pk').val(obj.id)
results_list.html(""); results_list.html('')
target.removeClass("is-invalid"); target.removeClass('is-invalid')
target.addClass("is-valid"); target.addClass('is-valid')
if (typeof autocompleted != 'undefined') if (typeof autocompleted !== 'undefined') { autocompleted(obj, prefix) }
autocompleted(obj, prefix) })
});
if (input === obj[name_field]) if (input === obj[name_field]) { $('#' + prefix + '_pk').val(obj.id) }
$("#" + prefix + "_pk").val(obj.id); })
});
if (results_list.children().length === 1 && e.originalEvent.keyCode >= 32) { if (results_list.children().length === 1 && e.originalEvent.keyCode >= 32) {
results_list.children().first().trigger("click"); results_list.children().first().trigger('click')
} }
}); })
}); })
$(".autocomplete-reset").click(function() { $('.autocomplete-reset').click(function () {
let name = $(this).attr("id").replace("_reset", ""); const name = $(this).attr('id').replace('_reset', '')
$("#" + name + "_pk").val(""); $('#' + name + '_pk').val('')
$("#" + name).val(""); $('#' + name).val('')
$("#" + name + "_list").html(""); $('#' + name + '_list').html('')
$(this).addClass("d-none"); $(this).addClass('d-none')
}); })
}); })

View File

@ -1,18 +1,16 @@
// 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
/** /**
* Convert balance in cents to a human readable amount * Convert balance in cents to a human readable amount
* @param value the balance, in cents * @param value the balance, in cents
* @returns {string} * @returns {string}
*/ */
function pretty_money (value) { function pretty_money (value) {
if (value % 100 === 0) if (value % 100 === 0) { return (value < 0 ? '- ' : '') + Math.floor(Math.abs(value) / 100) + ' €' } else {
return (value < 0 ? "- " : "") + Math.floor(Math.abs(value) / 100) + " €"; return (value < 0 ? '- ' : '') + Math.floor(Math.abs(value) / 100) + '.' +
else (Math.abs(value) % 100 < 10 ? '0' : '') + (Math.abs(value) % 100) + ' €'
return (value < 0 ? "- " : "") + Math.floor(Math.abs(value) / 100) + "." }
+ (Math.abs(value) % 100 < 10 ? "0" : "") + (Math.abs(value) % 100) + " €";
} }
/** /**
@ -22,18 +20,18 @@ function pretty_money (value) {
* @param timeout The delay (in millis) after that the message is auto-closed. If negative, then it is ignored. * @param timeout The delay (in millis) after that the message is auto-closed. If negative, then it is ignored.
*/ */
function addMsg (msg, alert_type, timeout = -1) { function addMsg (msg, alert_type, timeout = -1) {
let msgDiv = $("#messages"); const msgDiv = $('#messages')
let html = msgDiv.html(); let html = msgDiv.html()
let id = Math.floor(10000 * Math.random() + 1); const id = Math.floor(10000 * Math.random() + 1)
html += "<div class=\"alert alert-" + alert_type + " alert-dismissible\">" + html += '<div class="alert alert-' + alert_type + ' alert-dismissible">' +
"<button id=\"close-message-" + id + "\" class=\"close\" data-dismiss=\"alert\" href=\"#\"><span aria-hidden=\"true\">×</span></button>" '<button id="close-message-' + id + '" class="close" data-dismiss="alert" href="#"><span aria-hidden="true">×</span></button>' +
+ msg + "</div>\n"; msg + '</div>\n'
msgDiv.html(html); msgDiv.html(html)
if (timeout > 0) { if (timeout > 0) {
setTimeout(function () { setTimeout(function () {
$("#close-message-" + id).click(); $('#close-message-' + id).click()
}, timeout); }, timeout)
} }
} }
@ -44,33 +42,33 @@ function addMsg (msg, alert_type, timeout = -1) {
*/ */
function errMsg (errs_obj, timeout = -1) { function errMsg (errs_obj, timeout = -1) {
for (const err_msg of Object.values(errs_obj)) { for (const err_msg of Object.values(errs_obj)) {
addMsg(err_msg, 'danger', timeout); addMsg(err_msg, 'danger', timeout)
} }
} }
var reloadWithTurbolinks = (function () { var reloadWithTurbolinks = (function () {
var scrollPosition; var scrollPosition
function reload () { function reload () {
scrollPosition = [window.scrollX, window.scrollY]; scrollPosition = [window.scrollX, window.scrollY]
Turbolinks.visit(window.location.toString(), { action: 'replace' }) Turbolinks.visit(window.location.toString(), { action: 'replace' })
} }
document.addEventListener('turbolinks:load', function () { document.addEventListener('turbolinks:load', function () {
if (scrollPosition) { if (scrollPosition) {
window.scrollTo.apply(window, scrollPosition); window.scrollTo.apply(window, scrollPosition)
scrollPosition = null scrollPosition = null
} }
}); })
return reload; return reload
})(); })()
/** /**
* Reload the balance of the user on the right top corner * Reload the balance of the user on the right top corner
*/ */
function refreshBalance () { function refreshBalance () {
$("#user_balance").load("/ #user_balance"); $('#user_balance').load('/ #user_balance')
} }
/** /**
@ -79,15 +77,15 @@ function refreshBalance () {
* @param fun For each found note with the matched alias `alias`, fun(note, alias) is called. * @param fun For each found note with the matched alias `alias`, fun(note, alias) is called.
*/ */
function getMatchedNotes (pattern, fun) { function getMatchedNotes (pattern, fun) {
$.getJSON("/api/note/alias/?format=json&alias=" + pattern + "&search=user|club", fun); $.getJSON('/api/note/alias/?format=json&alias=' + pattern + '&search=user|club', fun)
} }
/** /**
* Generate a <li> entry with a given id and text * Generate a <li> entry with a given id and text
*/ */
function li (id, text, extra_css) { function li (id, text, extra_css) {
return "<li class=\"list-group-item py-1 px-2 d-flex justify-content-between align-items-center text-truncate " return '<li class="list-group-item py-1 px-2 d-flex justify-content-between align-items-center text-truncate ' +
+ (extra_css ? extra_css : "") + "\"" + " id=\"" + id + "\">" + text + "</li>\n"; (extra_css || '') + '"' + ' id="' + id + '">' + text + '</li>\n'
} }
/** /**
@ -95,24 +93,13 @@ function li (id, text, extra_css) {
* @param note The concerned note. * @param note The concerned note.
*/ */
function displayStyle (note) { function displayStyle (note) {
if (!note) if (!note) { return '' }
return ""; const balance = note.balance
let balance = note.balance; var css = ''
var css = ""; if (balance < -5000) { css += ' text-danger bg-dark' } else if (balance < -1000) { css += ' text-danger' } else if (balance < 0) { css += ' text-warning' } else if (!note.email_confirmed) { css += ' text-white bg-primary' } else if (!note.is_active || (note.membership && note.membership.date_end < new Date().toISOString())) { css += 'text-white bg-info' }
if (balance < -5000) return css
css += " text-danger bg-dark";
else if (balance < -1000)
css += " text-danger";
else if (balance < 0)
css += " text-warning";
else if (!note.email_confirmed)
css += " text-white bg-primary";
else if (!note.is_active || (note.membership && note.membership.date_end < new Date().toISOString()))
css += "text-white bg-info";
return css;
} }
/** /**
* Render note name and picture * Render note name and picture
* @param note The note to render * @param note The note to render
@ -122,20 +109,19 @@ function displayStyle (note) {
*/ */
function displayNote (note, alias, user_note_field = null, profile_pic_field = null) { function displayNote (note, alias, user_note_field = null, profile_pic_field = null) {
if (!note.display_image) { if (!note.display_image) {
note.display_image = '/static/member/img/default_picture.png'; note.display_image = '/static/member/img/default_picture.png'
} }
let img = note.display_image; const img = note.display_image
if (alias !== note.name && note.name) if (alias !== note.name && note.name) { alias += ' (aka. ' + note.name + ')' }
alias += " (aka. " + note.name + ")";
if (user_note_field !== null) { if (user_note_field !== null) {
$("#" + user_note_field).removeAttr('class'); $('#' + user_note_field).removeAttr('class')
$("#" + user_note_field).addClass(displayStyle(note)); $('#' + user_note_field).addClass(displayStyle(note))
$("#" + user_note_field).text(alias + (note.balance == null ? "" : (" :\n" + pretty_money(note.balance)))); $('#' + user_note_field).text(alias + (note.balance == null ? '' : (' :\n' + pretty_money(note.balance))))
if (profile_pic_field != null) { if (profile_pic_field != null) {
$("#" + profile_pic_field).attr('src', img); $('#' + profile_pic_field).attr('src', img)
$("#" + profile_pic_field + "_link").attr('href', note.resourcetype === "NoteUser" ? $('#' + profile_pic_field + '_link').attr('href', note.resourcetype === 'NoteUser'
"/accounts/user/" + note.user : note.resourcetype === "NoteClub" ? ? '/accounts/user/' + note.user : note.resourcetype === 'NoteClub'
"/accounts/club/" + note.club : "#"); ? '/accounts/club/' + note.club : '#')
} }
} }
} }
@ -152,35 +138,34 @@ function displayNote (note, alias, user_note_field = null, profile_pic_field = n
* (useful in consumptions, put null if not used) * (useful in consumptions, put null if not used)
* @returns an anonymous function to be compatible with jQuery events * @returns an anonymous function to be compatible with jQuery events
*/ */
function removeNote (d, note_prefix = "note", notes_display, note_list_id, user_note_field = null, profile_pic_field = null) { function removeNote (d, note_prefix = 'note', notes_display, note_list_id, user_note_field = null, profile_pic_field = null) {
return (function () { return function () {
let new_notes_display = []; const new_notes_display = []
let html = ""; let html = ''
notes_display.forEach(function (disp) { notes_display.forEach(function (disp) {
if (disp.quantity > 1 || disp.id !== d.id) { if (disp.quantity > 1 || disp.id !== d.id) {
disp.quantity -= disp.id === d.id ? 1 : 0; disp.quantity -= disp.id === d.id ? 1 : 0
new_notes_display.push(disp); new_notes_display.push(disp)
html += li(note_prefix + "_" + disp.id, disp.name html += li(note_prefix + '_' + disp.id, disp.name +
+ "<span class=\"badge badge-dark badge-pill\">" + disp.quantity + "</span>", '<span class="badge badge-dark badge-pill">' + disp.quantity + '</span>',
displayStyle(disp.note)); displayStyle(disp.note))
} }
}); })
notes_display.length = 0; notes_display.length = 0
new_notes_display.forEach(function (disp) { new_notes_display.forEach(function (disp) {
notes_display.push(disp); notes_display.push(disp)
}); })
$("#" + note_list_id).html(html); $('#' + note_list_id).html(html)
notes_display.forEach(function (disp) { notes_display.forEach(function (disp) {
let obj = $("#" + note_prefix + "_" + disp.id); const obj = $('#' + note_prefix + '_' + disp.id)
obj.click(removeNote(disp, note_prefix, notes_display, note_list_id, user_note_field, profile_pic_field)); obj.click(removeNote(disp, note_prefix, notes_display, note_list_id, user_note_field, profile_pic_field))
obj.hover(function () { obj.hover(function () {
if (disp.note) if (disp.note) { displayNote(disp.note, disp.name, user_note_field, profile_pic_field) }
displayNote(disp.note, disp.name, user_note_field, profile_pic_field); })
}); })
}); }
});
} }
/** /**
@ -199,9 +184,9 @@ function removeNote (d, note_prefix = "note", notes_display, note_list_id, user_
* the associated note is not displayed. * the associated note is not displayed.
* Useful for a consumption if the item is selected before. * Useful for a consumption if the item is selected before.
*/ */
function autoCompleteNote (field_id, note_list_id, notes, notes_display, alias_prefix = "alias", function autoCompleteNote (field_id, note_list_id, notes, notes_display, alias_prefix = 'alias',
note_prefix = "note", user_note_field = null, profile_pic_field = null, alias_click = null) { note_prefix = 'note', user_note_field = null, profile_pic_field = null, alias_click = null) {
let field = $("#" + field_id); const field = $('#' + field_id)
// Configure tooltip // Configure tooltip
field.tooltip({ field.tooltip({
@ -211,96 +196,90 @@ function autoCompleteNote (field_id, note_list_id, notes, notes_display, alias_p
trigger: 'manual', trigger: 'manual',
container: field.parent(), container: field.parent(),
fallbackPlacement: 'clockwise' fallbackPlacement: 'clockwise'
}); })
// When the user clicks elsewhere, we hide the tooltip // When the user clicks elsewhere, we hide the tooltip
$(document).click(function(e) { $(document).click(function (e) {
if (!e.target.id.startsWith(alias_prefix)) { if (!e.target.id.startsWith(alias_prefix)) {
field.tooltip("hide"); field.tooltip('hide')
} }
}); })
let old_pattern = null; let old_pattern = null
// Clear search on click // Clear search on click
field.click(function () { field.click(function () {
field.tooltip('hide'); field.tooltip('hide')
field.removeClass('is-invalid'); field.removeClass('is-invalid')
field.val(""); field.val('')
old_pattern = ""; old_pattern = ''
}); })
// When the user type "Enter", the first alias is clicked // When the user type "Enter", the first alias is clicked
field.keypress(function (event) { field.keypress(function (event) {
if (event.originalEvent.charCode === 13 && notes.length > 0) { if (event.originalEvent.charCode === 13 && notes.length > 0) {
let li_obj = field.parent().find("ul li").first(); const li_obj = field.parent().find('ul li').first()
displayNote(notes[0], li_obj.text(), user_note_field, profile_pic_field); displayNote(notes[0], li_obj.text(), user_note_field, profile_pic_field)
li_obj.trigger("click"); li_obj.trigger('click')
} }
}); })
// When the user type something, the matched aliases are refreshed // When the user type something, the matched aliases are refreshed
field.keyup(function (e) { field.keyup(function (e) {
field.removeClass('is-invalid'); field.removeClass('is-invalid')
if (e.originalEvent.charCode === 13) if (e.originalEvent.charCode === 13) { return }
return;
let pattern = field.val(); const pattern = field.val()
// If the pattern is not modified, we don't query the API // If the pattern is not modified, we don't query the API
if (pattern === old_pattern) if (pattern === old_pattern) { return }
return; old_pattern = pattern
old_pattern = pattern; notes.length = 0
notes.length = 0;
// get matched Alias with note associated // get matched Alias with note associated
if (pattern === "") { if (pattern === '') {
field.tooltip('hide'); field.tooltip('hide')
notes.length = 0; notes.length = 0
return; return
} }
$.getJSON("/api/note/consumer/?format=json&alias=" + pattern + "&search=user|club", $.getJSON('/api/note/consumer/?format=json&alias=' + pattern + '&search=user|club',
function (consumers) { function (consumers) {
// The response arrived too late, we stop the request // The response arrived too late, we stop the request
if (pattern !== $("#" + field_id).val()) if (pattern !== $('#' + field_id).val()) { return }
return;
// Build tooltip content // Build tooltip content
let aliases_matched_html = '<ul class="list-group list-group-flush">'; let aliases_matched_html = '<ul class="list-group list-group-flush">'
consumers.results.forEach(function (consumer) { consumers.results.forEach(function (consumer) {
let note = consumer.note; const note = consumer.note
note.email_confirmed = consumer.email_confirmed; note.email_confirmed = consumer.email_confirmed
if (consumer.hasOwnProperty("membership") && consumer.membership) if (consumer.hasOwnProperty('membership') && consumer.membership) { note.membership = consumer.membership } else { note.membership = undefined }
note.membership = consumer.membership; const extra_css = displayStyle(note)
else
note.membership = undefined;
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,
extra_css); extra_css)
notes.push(note); notes.push(note)
}); })
aliases_matched_html += '</ul>'; aliases_matched_html += '</ul>'
// Show tooltip // Show tooltip
field.attr('data-original-title', aliases_matched_html).tooltip('show'); field.attr('data-original-title', aliases_matched_html).tooltip('show')
consumers.results.forEach(function (consumer) { consumers.results.forEach(function (consumer) {
let consumer_obj = $("#" + alias_prefix + "_" + consumer.id); const consumer_obj = $('#' + alias_prefix + '_' + consumer.id)
consumer_obj.hover(function () { consumer_obj.hover(function () {
displayNote(consumer.note, consumer.name, user_note_field, profile_pic_field) displayNote(consumer.note, consumer.name, user_note_field, profile_pic_field)
}); })
consumer_obj.click(function () { consumer_obj.click(function () {
var disp = null; var disp = null
notes_display.forEach(function (d) { notes_display.forEach(function (d) {
// We compare the alias ids // We compare the alias ids
if (d.id === consumer.id) { if (d.id === consumer.id) {
d.quantity += 1; d.quantity += 1
disp = d; disp = d
} }
}); })
// In the other case, we add a new emitter // In the other case, we add a new emitter
if (disp == null) { if (disp == null) {
disp = { disp = {
@ -308,94 +287,90 @@ function autoCompleteNote (field_id, note_list_id, notes, notes_display, alias_p
id: consumer.id, id: consumer.id,
note: consumer.note, note: consumer.note,
quantity: 1 quantity: 1
}; }
notes_display.push(disp); notes_display.push(disp)
} }
// If the function alias_click exists, it is called. If it doesn't return true, then the notes are // If the function alias_click exists, it is called. If it doesn't return true, then the notes are
// note displayed. Useful for a consumption when a button is already clicked // note displayed. Useful for a consumption when a button is already clicked
if (alias_click && !alias_click()) if (alias_click && !alias_click()) { return }
return;
let note_list = $("#" + note_list_id); const note_list = $('#' + note_list_id)
let html = ""; let html = ''
notes_display.forEach(function (disp) { notes_display.forEach(function (disp) {
html += li(note_prefix + "_" + disp.id, html += li(note_prefix + '_' + disp.id,
disp.name disp.name +
+ "<span class=\"badge badge-dark badge-pill\">" '<span class="badge badge-dark badge-pill">' +
+ disp.quantity + "</span>", disp.quantity + '</span>',
displayStyle(disp.note)); displayStyle(disp.note))
}); })
// Emitters are displayed // Emitters are displayed
note_list.html(html); note_list.html(html)
// Update tooltip position // Update tooltip position
field.tooltip('update'); field.tooltip('update')
notes_display.forEach(function (disp) { notes_display.forEach(function (disp) {
let line_obj = $("#" + note_prefix + "_" + disp.id); const line_obj = $('#' + note_prefix + '_' + disp.id)
// Hover an emitter display also the profile picture // Hover an emitter display also the profile picture
line_obj.hover(function () { line_obj.hover(function () {
displayNote(disp.note, disp.name, user_note_field, profile_pic_field); displayNote(disp.note, disp.name, user_note_field, profile_pic_field)
}); })
// When an emitter is clicked, it is removed // When an emitter is clicked, it is removed
line_obj.click(removeNote(disp, note_prefix, notes_display, note_list_id, user_note_field, line_obj.click(removeNote(disp, note_prefix, notes_display, note_list_id, user_note_field,
profile_pic_field)); profile_pic_field))
}); })
})
})
})// end getJSON alias
}) })
});
});// end getJSON alias
});
}// end function autocomplete }// end function autocomplete
// When a validate button is clicked, we switch the validation status // When a validate button is clicked, we switch the validation status
function de_validate (id, validated, resourcetype) { function de_validate (id, validated, resourcetype) {
let validate_obj = $("#validate_" + id); const validate_obj = $('#validate_' + id)
if (validate_obj.data("pending")) if (validate_obj.data('pending'))
// The button is already clicked // The button is already clicked
return; { return }
let invalidity_reason = $("#invalidity_reason_" + id).val(); const invalidity_reason = $('#invalidity_reason_' + id).val()
validate_obj.html("<strong style=\"font-size: 16pt;\">⟳</strong>"); validate_obj.html('<strong style="font-size: 16pt;">⟳</strong>')
validate_obj.data("pending", true); validate_obj.data('pending', true)
// Perform a PATCH request to the API in order to update the transaction // Perform a PATCH request to the API in order to update the transaction
// If the user has insufficient rights, an error message will appear // If the user has insufficient rights, an error message will appear
$.ajax({ $.ajax({
"url": "/api/note/transaction/transaction/" + id + "/", url: '/api/note/transaction/transaction/' + id + '/',
type: "PATCH", type: 'PATCH',
dataType: "json", dataType: 'json',
headers: { headers: {
"X-CSRFTOKEN": CSRF_TOKEN 'X-CSRFTOKEN': CSRF_TOKEN
}, },
data: { data: {
"resourcetype": resourcetype, resourcetype: resourcetype,
"valid": !validated, valid: !validated,
"invalidity_reason": invalidity_reason, invalidity_reason: invalidity_reason
}, },
success: function () { success: function () {
refreshBalance(); refreshBalance()
// error if this method doesn't exist. Please define it. // error if this method doesn't exist. Please define it.
refreshHistory(); refreshHistory()
}, },
error: function (err) { error: function (err) {
let errObj = JSON.parse(err.responseText); const errObj = JSON.parse(err.responseText)
let error = errObj["detail"] ? errObj["detail"] : errObj["non_field_errors"]; let error = errObj.detail ? errObj.detail : errObj.non_field_errors
if (!error) if (!error) { error = err.responseText }
error = err.responseText; addMsg('Une erreur est survenue lors de la validation/dévalidation ' +
addMsg("Une erreur est survenue lors de la validation/dévalidation " + 'de cette transaction : ' + error, 'danger')
"de cette transaction : " + error, "danger");
refreshBalance(); refreshBalance()
// error if this method doesn't exist. Please define it. // error if this method doesn't exist. Please define it.
refreshHistory(); refreshHistory()
} }
}); })
} }
/** /**
@ -404,10 +379,10 @@ function de_validate (id, validated, resourcetype) {
* @param wait Debounced milliseconds * @param wait Debounced milliseconds
*/ */
function debounce (callback, wait) { function debounce (callback, wait) {
let timeout; let timeout
return (...args) => { return (...args) => {
const context = this; const context = this
clearTimeout(timeout); clearTimeout(timeout)
timeout = setTimeout(() => callback.apply(context, args), wait); timeout = setTimeout(() => callback.apply(context, args), wait)
}; }
} }

View File

@ -2,95 +2,92 @@
// 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. // When a transaction is performed, lock the interface to prevent spam clicks.
var LOCK = false; var LOCK = false
/** /**
* Refresh the history table on the consumptions page. * Refresh the history table on the consumptions page.
*/ */
function refreshHistory() { function refreshHistory () {
$("#history").load("/note/consos/ #history"); $('#history').load('/note/consos/ #history')
$("#most_used").load("/note/consos/ #most_used"); $('#most_used').load('/note/consos/ #most_used')
} }
$(document).ready(function() { $(document).ready(function () {
// If hash of a category in the URL, then select this category // If hash of a category in the URL, then select this category
// else select the first one // else select the first one
if (location.hash) { if (location.hash) {
$("a[href='" + location.hash + "']").tab("show"); $("a[href='" + location.hash + "']").tab('show')
} else { } else {
$("a[data-toggle='tab']").first().tab("show"); $("a[data-toggle='tab']").first().tab('show')
} }
// When selecting a category, change URL // When selecting a category, change URL
$(document.body).on("click", "a[data-toggle='tab']", function() { $(document.body).on('click', "a[data-toggle='tab']", function () {
location.hash = this.getAttribute("href"); location.hash = this.getAttribute('href')
}); })
// Switching in double consumptions mode should update the layout // Switching in double consumptions mode should update the layout
$("#double_conso").change(function() { $('#double_conso').change(function () {
$("#consos_list_div").removeClass('d-none'); $('#consos_list_div').removeClass('d-none')
$("#user_select_div").attr('class', 'col-xl-4'); $('#user_select_div').attr('class', 'col-xl-4')
$("#infos_div").attr('class', 'col-sm-5 col-xl-6'); $('#infos_div').attr('class', 'col-sm-5 col-xl-6')
let note_list_obj = $("#note_list"); const note_list_obj = $('#note_list')
if (buttons.length > 0 && note_list_obj.text().length > 0) { if (buttons.length > 0 && note_list_obj.text().length > 0) {
$("#consos_list").html(note_list_obj.html()); $('#consos_list').html(note_list_obj.html())
note_list_obj.html(""); note_list_obj.html('')
buttons.forEach(function(button) { buttons.forEach(function (button) {
$("#conso_button_" + button.id).click(function() { $('#conso_button_' + button.id).click(function () {
if (LOCK) if (LOCK) { return }
return; removeNote(button, 'conso_button', buttons, 'consos_list')()
removeNote(button, "conso_button", buttons,"consos_list")(); })
}); })
});
} }
}); })
$("#single_conso").change(function() { $('#single_conso').change(function () {
$("#consos_list_div").addClass('d-none'); $('#consos_list_div').addClass('d-none')
$("#user_select_div").attr('class', 'col-xl-7'); $('#user_select_div').attr('class', 'col-xl-7')
$("#infos_div").attr('class', 'col-sm-5 col-md-4'); $('#infos_div').attr('class', 'col-sm-5 col-md-4')
let consos_list_obj = $("#consos_list"); const consos_list_obj = $('#consos_list')
if (buttons.length > 0) { if (buttons.length > 0) {
if (notes_display.length === 0 && consos_list_obj.text().length > 0) { if (notes_display.length === 0 && consos_list_obj.text().length > 0) {
$("#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(function() { $('#conso_button_' + button.id).click(function () {
if (LOCK) if (LOCK) { return }
return; removeNote(button, 'conso_button', buttons, 'note_list')()
removeNote(button, "conso_button", buttons,"note_list")(); })
}); })
}); } else {
} buttons.length = 0
else { consos_list_obj.html('')
buttons.length = 0;
consos_list_obj.html("");
} }
} }
}); })
// Ensure we begin in single consumption. Fix issue with TurboLinks and BootstrapJS // Ensure we begin in single consumption. Fix issue with TurboLinks and BootstrapJS
$("label[for='double_conso']").removeClass('active'); $("label[for='double_conso']").removeClass('active')
$("#consume_all").click(consumeAll); $('#consume_all').click(consumeAll)
}); })
notes = []; notes = []
notes_display = []; notes_display = []
buttons = []; buttons = []
// When the user searches an alias, we update the auto-completion // When the user searches an alias, we update the auto-completion
autoCompleteNote("note", "note_list", notes, notes_display, autoCompleteNote('note', 'note_list', notes, notes_display,
"alias", "note", "user_note", "profile_pic", function() { 'alias', 'note', 'user_note', 'profile_pic', function () {
if (buttons.length > 0 && $("#single_conso").is(":checked")) { if (buttons.length > 0 && $('#single_conso').is(':checked')) {
consumeAll(); consumeAll()
return false; return false
} }
return true; return true
}); })
/** /**
* Add a transaction from a button. * Add a transaction from a button.
@ -102,14 +99,14 @@ autoCompleteNote("note", "note_list", notes, notes_display,
* @param template_id The identifier of the button * @param template_id The identifier of the button
* @param template_name The name of the button * @param template_name The name of the button
*/ */
function addConso(dest, amount, type, category_id, category_name, template_id, template_name) { function addConso (dest, amount, type, category_id, category_name, template_id, template_name) {
var button = null; var button = null
buttons.forEach(function(b) { buttons.forEach(function (b) {
if (b.id === template_id) { if (b.id === template_id) {
b.quantity += 1; b.quantity += 1
button = b; button = b
} }
}); })
if (button == null) { if (button == null) {
button = { button = {
id: template_id, id: template_id,
@ -120,85 +117,80 @@ function addConso(dest, amount, type, category_id, category_name, template_id, t
type: type, type: type,
category_id: category_id, category_id: category_id,
category_name: category_name category_name: category_name
}; }
buttons.push(button); buttons.push(button)
} }
let dc_obj = $("#double_conso"); const dc_obj = $('#double_conso')
if (dc_obj.is(":checked") || notes_display.length === 0) { if (dc_obj.is(':checked') || notes_display.length === 0) {
let list = dc_obj.is(":checked") ? "consos_list" : "note_list"; const list = dc_obj.is(':checked') ? 'consos_list' : 'note_list'
let html = ""; let html = ''
buttons.forEach(function(button) { buttons.forEach(function (button) {
html += li("conso_button_" + button.id, button.name html += li('conso_button_' + button.id, button.name +
+ "<span class=\"badge badge-dark badge-pill\">" + button.quantity + "</span>"); '<span class="badge badge-dark badge-pill">' + button.quantity + '</span>')
}); })
$("#" + list).html(html); $('#' + list).html(html)
buttons.forEach(function(button) { buttons.forEach(function (button) {
$("#conso_button_" + button.id).click(function() { $('#conso_button_' + button.id).click(function () {
if (LOCK) if (LOCK) { return }
return; removeNote(button, 'conso_button', buttons, list)()
removeNote(button, "conso_button", buttons, list)(); })
}); })
}); } else { consumeAll() }
}
else
consumeAll();
} }
/** /**
* Reset the page as its initial state. * Reset the page as its initial state.
*/ */
function reset() { function reset () {
notes_display.length = 0; notes_display.length = 0
notes.length = 0; notes.length = 0
buttons.length = 0; buttons.length = 0
$("#note_list").html(""); $('#note_list').html('')
$("#consos_list").html(""); $('#consos_list').html('')
$("#note").val(""); $('#note').val('')
$("#note").attr("data-original-title", "").tooltip("hide"); $('#note').attr('data-original-title', '').tooltip('hide')
$("#profile_pic").attr("src", "/static/member/img/default_picture.png"); $('#profile_pic').attr('src', '/static/member/img/default_picture.png')
$("#profile_pic_link").attr("href", "#"); $('#profile_pic_link').attr('href', '#')
refreshHistory(); refreshHistory()
refreshBalance(); refreshBalance()
LOCK = false; LOCK = false
} }
/** /**
* 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) if (LOCK) { return }
return;
LOCK = true; LOCK = true
let error = false; let error = false
if (notes_display.length === 0) { if (notes_display.length === 0) {
$("#note").addClass('is-invalid'); $('#note').addClass('is-invalid')
$("#note_list").html(li("", "<strong>Ajoutez des émetteurs.</strong>", "text-danger")); $('#note_list').html(li('', '<strong>Ajoutez des émetteurs.</strong>', 'text-danger'))
error = true; error = true
} }
if (buttons.length === 0) { if (buttons.length === 0) {
$("#consos_list").html(li("", "<strong>Ajoutez des consommations.</strong>", "text-danger")); $('#consos_list').html(li('', '<strong>Ajoutez des consommations.</strong>', 'text-danger'))
error = true; error = true
} }
if (error) { if (error) {
LOCK = false; LOCK = false
return; return
} }
notes_display.forEach(function(note_display) { notes_display.forEach(function (note_display) {
buttons.forEach(function(button) { buttons.forEach(function (button) {
consume(note_display.note, note_display.name, button.dest, button.quantity * note_display.quantity, button.amount, consume(note_display.note, note_display.name, button.dest, button.quantity * note_display.quantity, button.amount,
button.name + " (" + button.category_name + ")", button.type, button.category_id, button.id); button.name + ' (' + button.category_name + ')', button.type, button.category_id, button.id)
}); })
}); })
} }
/** /**
@ -213,58 +205,60 @@ function consumeAll() {
* @param category The category id of the button (type: int) * @param category The category id of the button (type: int)
* @param template The button id (type: int) * @param template The button id (type: int)
*/ */
function consume(source, source_alias, dest, quantity, amount, reason, type, category, template) { function consume (source, source_alias, dest, quantity, amount, reason, type, category, template) {
$.post("/api/note/transaction/transaction/", $.post('/api/note/transaction/transaction/',
{ {
"csrfmiddlewaretoken": CSRF_TOKEN, csrfmiddlewaretoken: CSRF_TOKEN,
"quantity": quantity, quantity: quantity,
"amount": amount, amount: amount,
"reason": reason, reason: reason,
"valid": true, valid: true,
"polymorphic_ctype": type, polymorphic_ctype: type,
"resourcetype": "RecurrentTransaction", resourcetype: 'RecurrentTransaction',
"source": source.id, source: source.id,
"source_alias": source_alias, source_alias: source_alias,
"destination": dest, destination: dest,
"template": template template: template
}) })
.done(function () { .done(function () {
if (!isNaN(source.balance)) { if (!isNaN(source.balance)) {
let newBalance = source.balance - quantity * amount; const newBalance = source.balance - quantity * amount
if (newBalance <= -5000) if (newBalance <= -5000) {
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 sévère.", 'succès, mais la note émettrice ' + source_alias + ' est en négatif sévère.',
"danger", 30000); 'danger', 30000)
else if (newBalance < 0) } else if (newBalance < 0) {
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.membership && source.membership.date_end < new Date().toISOString())
addMsg("Attention : la note émettrice " + source.name + " n'est plus adhérente.",
"danger", 30000);
} }
reset(); if (source.membership && source.membership.date_end < new Date().toISOString()) {
addMsg('Attention : la note émettrice ' + source.name + " n'est plus adhérente.",
'danger', 30000)
}
}
reset()
}).fail(function (e) { }).fail(function (e) {
$.post("/api/note/transaction/transaction/", $.post('/api/note/transaction/transaction/',
{ {
"csrfmiddlewaretoken": CSRF_TOKEN, csrfmiddlewaretoken: CSRF_TOKEN,
"quantity": quantity, quantity: quantity,
"amount": amount, amount: amount,
"reason": reason, reason: reason,
"valid": false, valid: false,
"invalidity_reason": "Solde insuffisant", invalidity_reason: 'Solde insuffisant',
"polymorphic_ctype": type, polymorphic_ctype: type,
"resourcetype": "RecurrentTransaction", resourcetype: 'RecurrentTransaction',
"source": source, source: source,
"source_alias": source_alias, source_alias: source_alias,
"destination": dest, destination: dest,
"template": template template: template
}).done(function() { }).done(function () {
reset(); reset()
addMsg("La transaction n'a pas pu être validée pour cause de solde insuffisant.", "danger", 10000); addMsg("La transaction n'a pas pu être validée pour cause de solde insuffisant.", 'danger', 10000)
}).fail(function () { }).fail(function () {
reset(); reset()
errMsg(e.responseJSON); errMsg(e.responseJSON)
}); })
}); })
} }

View File

@ -9,121 +9,120 @@
* Licensed under the New BSD License * Licensed under the New BSD License
* See: http://www.opensource.org/licenses/bsd-license.php * See: http://www.opensource.org/licenses/bsd-license.php
*/ */
;(function($) { ;(function ($) {
$.fn.formset = function(opts) $.fn.formset = function (opts) {
{ var options = $.extend({}, $.fn.formset.defaults, opts)
var options = $.extend({}, $.fn.formset.defaults, opts), var flatExtraClasses = options.extraClasses.join(' ')
flatExtraClasses = options.extraClasses.join(' '), var totalForms = $('#id_' + options.prefix + '-TOTAL_FORMS')
totalForms = $('#id_' + options.prefix + '-TOTAL_FORMS'), var maxForms = $('#id_' + options.prefix + '-MAX_NUM_FORMS')
maxForms = $('#id_' + options.prefix + '-MAX_NUM_FORMS'), var minForms = $('#id_' + options.prefix + '-MIN_NUM_FORMS')
minForms = $('#id_' + options.prefix + '-MIN_NUM_FORMS'), var childElementSelector = 'input,select,textarea,label,div'
childElementSelector = 'input,select,textarea,label,div', var $$ = $(this)
$$ = $(this),
applyExtraClasses = function(row, ndx) { var applyExtraClasses = function (row, ndx) {
if (options.extraClasses) { if (options.extraClasses) {
row.removeClass(flatExtraClasses); row.removeClass(flatExtraClasses)
row.addClass(options.extraClasses[ndx % options.extraClasses.length]); row.addClass(options.extraClasses[ndx % options.extraClasses.length])
}
} }
},
updateElementIndex = function(elem, prefix, ndx) { var updateElementIndex = function (elem, prefix, ndx) {
var idRegex = new RegExp(prefix + '-(\\d+|__prefix__)-'), var idRegex = new RegExp(prefix + '-(\\d+|__prefix__)-')
replacement = prefix + '-' + ndx + '-'; var replacement = prefix + '-' + ndx + '-'
if (elem.attr("for")) elem.attr("for", elem.attr("for").replace(idRegex, replacement)); if (elem.attr('for')) elem.attr('for', elem.attr('for').replace(idRegex, replacement))
if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement)); if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement))
if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement)); if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement))
}, }
hasChildElements = function(row) { var hasChildElements = function (row) {
return row.find(childElementSelector).length > 0; return row.find(childElementSelector).length > 0
}, }
showAddButton = function() { var showAddButton = function () {
return maxForms.length == 0 || // For Django versions pre 1.2 return maxForms.length == 0 || // For Django versions pre 1.2
(maxForms.val() == '' || (maxForms.val() - totalForms.val() > 0)); (maxForms.val() == '' || (maxForms.val() - totalForms.val() > 0))
}, }
/** /**
* Indicates whether delete link(s) can be displayed - when total forms > min forms * Indicates whether delete link(s) can be displayed - when total forms > min forms
*/ */
showDeleteLinks = function() { var showDeleteLinks = function () {
return minForms.length == 0 || // For Django versions pre 1.7 return minForms.length == 0 || // For Django versions pre 1.7
(minForms.val() == '' || (totalForms.val() - minForms.val() > 0)); (minForms.val() == '' || (totalForms.val() - minForms.val() > 0))
}, }
insertDeleteLink = function(row) { var insertDeleteLink = function (row) {
var delCssSelector = $.trim(options.deleteCssClass).replace(/\s+/g, '.'), var delCssSelector = $.trim(options.deleteCssClass).replace(/\s+/g, '.')
addCssSelector = $.trim(options.addCssClass).replace(/\s+/g, '.'); var addCssSelector = $.trim(options.addCssClass).replace(/\s+/g, '.')
var delButtonHTML = '<a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a>'; var delButtonHTML = '<a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText + '</a>'
if (options.deleteContainerClass) { if (options.deleteContainerClass) {
// If we have a specific container for the remove button, // If we have a specific container for the remove button,
// place it as the last child of that container: // place it as the last child of that container:
row.find('[class*="' + options.deleteContainerClass + '"]').append(delButtonHTML); row.find('[class*="' + options.deleteContainerClass + '"]').append(delButtonHTML)
} else if (row.is('TR')) { } else if (row.is('TR')) {
// If the forms are laid out in table rows, insert // If the forms are laid out in table rows, insert
// the remove button into the last table cell: // the remove button into the last table cell:
row.children('td:last').append(delButtonHTML); row.children('td:last').append(delButtonHTML)
} else if (row.is('UL') || row.is('OL')) { } else if (row.is('UL') || row.is('OL')) {
// If they're laid out as an ordered/unordered list, // If they're laid out as an ordered/unordered list,
// insert an <li> after the last list item: // insert an <li> after the last list item:
row.append('<li>' + delButtonHTML + '</li>'); row.append('<li>' + delButtonHTML + '</li>')
} else { } else {
// Otherwise, just insert the remove button as the // Otherwise, just insert the remove button as the
// last child element of the form's container: // last child element of the form's container:
row.append(delButtonHTML); row.append(delButtonHTML)
} }
// Check if we're under the minimum number of forms - not to display delete link at rendering // Check if we're under the minimum number of forms - not to display delete link at rendering
if (!showDeleteLinks()){ if (!showDeleteLinks()) {
row.find('a.' + delCssSelector).hide(); row.find('a.' + delCssSelector).hide()
} }
row.find('a.' + delCssSelector).click(function() { row.find('a.' + delCssSelector).click(function () {
var row = $(this).parents('.' + options.formCssClass), var row = $(this).parents('.' + options.formCssClass)
del = row.find('input:hidden[id $= "-DELETE"]'), var del = row.find('input:hidden[id $= "-DELETE"]')
buttonRow = row.siblings("a." + addCssSelector + ', .' + options.formCssClass + '-add'), var buttonRow = row.siblings('a.' + addCssSelector + ', .' + options.formCssClass + '-add')
forms; var forms
if (del.length) { if (del.length) {
// We're dealing with an inline formset. // We're dealing with an inline formset.
// Rather than remove this form from the DOM, we'll mark it as deleted // Rather than remove this form from the DOM, we'll mark it as deleted
// and hide it, then let Django handle the deleting: // and hide it, then let Django handle the deleting:
del.val('on'); del.val('on')
row.hide(); row.hide()
forms = $('.' + options.formCssClass).not(':hidden'); forms = $('.' + options.formCssClass).not(':hidden')
} else { } else {
row.remove(); row.remove()
// Update the TOTAL_FORMS count: // Update the TOTAL_FORMS count:
forms = $('.' + options.formCssClass).not('.formset-custom-template'); forms = $('.' + options.formCssClass).not('.formset-custom-template')
totalForms.val(forms.length); totalForms.val(forms.length)
} }
for (var i=0, formCount=forms.length; i<formCount; i++) { for (var i = 0, formCount = forms.length; i < formCount; i++) {
// Apply `extraClasses` to form rows so they're nicely alternating: // Apply `extraClasses` to form rows so they're nicely alternating:
applyExtraClasses(forms.eq(i), i); applyExtraClasses(forms.eq(i), i)
if (!del.length) { if (!del.length) {
// Also update names and IDs for all child controls (if this isn't // Also update names and IDs for all child controls (if this isn't
// a delete-able inline formset) so they remain in sequence: // a delete-able inline formset) so they remain in sequence:
forms.eq(i).find(childElementSelector).each(function() { forms.eq(i).find(childElementSelector).each(function () {
updateElementIndex($(this), options.prefix, i); updateElementIndex($(this), options.prefix, i)
}); })
} }
} }
// Check if we've reached the minimum number of forms - hide all delete link(s) // Check if we've reached the minimum number of forms - hide all delete link(s)
if (!showDeleteLinks()){ if (!showDeleteLinks()) {
$('a.' + delCssSelector).each(function(){$(this).hide();}); $('a.' + delCssSelector).each(function () { $(this).hide() })
} }
// Check if we need to show the add button: // Check if we need to show the add button:
if (buttonRow.is(':hidden') && showAddButton()) buttonRow.show(); if (buttonRow.is(':hidden') && showAddButton()) buttonRow.show()
// If a post-delete callback was provided, call it with the deleted form: // If a post-delete callback was provided, call it with the deleted form:
if (options.removed) options.removed(row); if (options.removed) options.removed(row)
return false; return false
}); })
}; }
$$.each(function(i) { $$.each(function (i) {
var row = $(this), var row = $(this)
del = row.find('input:checkbox[id $= "-DELETE"]'); var del = row.find('input:checkbox[id $= "-DELETE"]')
if (del.length) { if (del.length) {
// If you specify "can_delete = True" when creating an inline formset, // If you specify "can_delete = True" when creating an inline formset,
// Django adds a checkbox to each form in the formset. // Django adds a checkbox to each form in the formset.
@ -131,103 +130,103 @@
if (del.is(':checked')) { if (del.is(':checked')) {
// If an inline formset containing deleted forms fails validation, make sure // If an inline formset containing deleted forms fails validation, make sure
// we keep the forms hidden (thanks for the bug report and suggested fix Mike) // we keep the forms hidden (thanks for the bug report and suggested fix Mike)
del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" value="on" />'); del.before('<input type="hidden" name="' + del.attr('name') + '" id="' + del.attr('id') + '" value="on" />')
row.hide(); row.hide()
} else { } else {
del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" />'); del.before('<input type="hidden" name="' + del.attr('name') + '" id="' + del.attr('id') + '" />')
} }
// Hide any labels associated with the DELETE checkbox: // Hide any labels associated with the DELETE checkbox:
$('label[for="' + del.attr('id') + '"]').hide(); $('label[for="' + del.attr('id') + '"]').hide()
del.remove(); del.remove()
} }
if (hasChildElements(row)) { if (hasChildElements(row)) {
row.addClass(options.formCssClass); row.addClass(options.formCssClass)
if (row.is(':visible')) { if (row.is(':visible')) {
insertDeleteLink(row); insertDeleteLink(row)
applyExtraClasses(row, i); applyExtraClasses(row, i)
} }
} }
}); })
if ($$.length) { if ($$.length) {
var hideAddButton = !showAddButton(), var hideAddButton = !showAddButton()
addButton, template; var addButton; var template
if (options.formTemplate) { if (options.formTemplate) {
// If a form template was specified, we'll clone it to generate new form instances: // If a form template was specified, we'll clone it to generate new form instances:
template = (options.formTemplate instanceof $) ? options.formTemplate : $(options.formTemplate); template = (options.formTemplate instanceof $) ? options.formTemplate : $(options.formTemplate)
template.removeAttr('id').addClass(options.formCssClass + ' formset-custom-template'); template.removeAttr('id').addClass(options.formCssClass + ' formset-custom-template')
template.find(childElementSelector).each(function() { template.find(childElementSelector).each(function () {
updateElementIndex($(this), options.prefix, '__prefix__'); updateElementIndex($(this), options.prefix, '__prefix__')
}); })
insertDeleteLink(template); insertDeleteLink(template)
} else { } else {
// Otherwise, use the last form in the formset; this works much better if you've got // Otherwise, use the last form in the formset; this works much better if you've got
// extra (>= 1) forms (thnaks to justhamade for pointing this out): // extra (>= 1) forms (thnaks to justhamade for pointing this out):
if (options.hideLastAddForm) $('.' + options.formCssClass + ':last').hide(); if (options.hideLastAddForm) $('.' + options.formCssClass + ':last').hide()
template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id'); template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id')
template.find('input:hidden[id $= "-DELETE"]').remove(); template.find('input:hidden[id $= "-DELETE"]').remove()
// Clear all cloned fields, except those the user wants to keep (thanks to brunogola for the suggestion): // Clear all cloned fields, except those the user wants to keep (thanks to brunogola for the suggestion):
template.find(childElementSelector).not(options.keepFieldValues).each(function() { template.find(childElementSelector).not(options.keepFieldValues).each(function () {
var elem = $(this); var elem = $(this)
// If this is a checkbox or radiobutton, uncheck it. // If this is a checkbox or radiobutton, uncheck it.
// This fixes Issue 1, reported by Wilson.Andrew.J: // This fixes Issue 1, reported by Wilson.Andrew.J:
if (elem.is('input:checkbox') || elem.is('input:radio')) { if (elem.is('input:checkbox') || elem.is('input:radio')) {
elem.attr('checked', false); elem.attr('checked', false)
} else { } else {
elem.val(''); elem.val('')
} }
}); })
} }
// FIXME: Perhaps using $.data would be a better idea? // FIXME: Perhaps using $.data would be a better idea?
options.formTemplate = template; options.formTemplate = template
var addButtonHTML = '<a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a>'; var addButtonHTML = '<a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a>'
if (options.addContainerClass) { if (options.addContainerClass) {
// If we have a specific container for the "add" button, // If we have a specific container for the "add" button,
// place it as the last child of that container: // place it as the last child of that container:
var addContainer = $('[class*="' + options.addContainerClass + '"'); var addContainer = $('[class*="' + options.addContainerClass + '"')
addContainer.append(addButtonHTML); addContainer.append(addButtonHTML)
addButton = addContainer.find('[class="' + options.addCssClass + '"]'); addButton = addContainer.find('[class="' + options.addCssClass + '"]')
} else if ($$.is('TR')) { } else if ($$.is('TR')) {
// If forms are laid out as table rows, insert the // If forms are laid out as table rows, insert the
// "add" button in a new table row: // "add" button in a new table row:
var numCols = $$.eq(0).children().length, // This is a bit of an assumption :| var numCols = $$.eq(0).children().length // This is a bit of an assumption :|
buttonRow = $('<tr><td colspan="' + numCols + '">' + addButtonHTML + '</tr>').addClass(options.formCssClass + '-add'); var buttonRow = $('<tr><td colspan="' + numCols + '">' + addButtonHTML + '</tr>').addClass(options.formCssClass + '-add')
$$.parent().append(buttonRow); $$.parent().append(buttonRow)
addButton = buttonRow.find('a'); addButton = buttonRow.find('a')
} else { } else {
// Otherwise, insert it immediately after the last form: // Otherwise, insert it immediately after the last form:
$$.filter(':last').after(addButtonHTML); $$.filter(':last').after(addButtonHTML)
addButton = $$.filter(':last').next(); addButton = $$.filter(':last').next()
} }
if (hideAddButton) addButton.hide(); if (hideAddButton) addButton.hide()
addButton.click(function() { addButton.click(function () {
var formCount = parseInt(totalForms.val()), var formCount = parseInt(totalForms.val())
row = options.formTemplate.clone(true).removeClass('formset-custom-template'), var row = options.formTemplate.clone(true).removeClass('formset-custom-template')
buttonRow = $($(this).parents('tr.' + options.formCssClass + '-add').get(0) || this), var buttonRow = $($(this).parents('tr.' + options.formCssClass + '-add').get(0) || this)
delCssSelector = $.trim(options.deleteCssClass).replace(/\s+/g, '.'); var delCssSelector = $.trim(options.deleteCssClass).replace(/\s+/g, '.')
applyExtraClasses(row, formCount); applyExtraClasses(row, formCount)
row.insertBefore(buttonRow).show(); row.insertBefore(buttonRow).show()
row.find(childElementSelector).each(function() { row.find(childElementSelector).each(function () {
updateElementIndex($(this), options.prefix, formCount); updateElementIndex($(this), options.prefix, formCount)
}); })
totalForms.val(formCount + 1); totalForms.val(formCount + 1)
// Check if we're above the minimum allowed number of forms -> show all delete link(s) // Check if we're above the minimum allowed number of forms -> show all delete link(s)
if (showDeleteLinks()){ if (showDeleteLinks()) {
$('a.' + delCssSelector).each(function(){$(this).show();}); $('a.' + delCssSelector).each(function () { $(this).show() })
} }
// Check if we've exceeded the maximum allowed number of forms: // Check if we've exceeded the maximum allowed number of forms:
if (!showAddButton()) buttonRow.hide(); if (!showAddButton()) buttonRow.hide()
// If a post-add callback was supplied, call it with the added form: // If a post-add callback was supplied, call it with the added form:
if (options.added) options.added(row); if (options.added) options.added(row)
return false; return false
}); })
} }
return $$; return $$
}; }
/* Setup plugin defaults */ /* Setup plugin defaults */
$.fn.formset.defaults = { $.fn.formset.defaults = {
@ -245,5 +244,5 @@
added: null, // Function called each time a new form is added added: null, // Function called each time a new form is added
removed: null, // Function called each time a form is deleted removed: null, // Function called each time a form is deleted
hideLastAddForm: false // When set to true, hide last empty add form (becomes visible when clicking on add button) hideLastAddForm: false // When set to true, hide last empty add form (becomes visible when clicking on add button)
}; }
})(jQuery); })(jQuery)

View File

@ -6,13 +6,13 @@
let cursor = 0 let cursor = 0
const KONAMI_CODE = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65] const KONAMI_CODE = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65]
function afterKonami() { function afterKonami () {
// Load Rythm.js // Load Rythm.js
var rythmScript = document.createElement('script') var rythmScript = document.createElement('script')
rythmScript.setAttribute('src','//unpkg.com/rythm.js@2.2.5/rythm.min.js') rythmScript.setAttribute('src', '//unpkg.com/rythm.js@2.2.5/rythm.min.js')
document.head.appendChild(rythmScript) document.head.appendChild(rythmScript)
rythmScript.addEventListener('load', function() { rythmScript.addEventListener('load', function () {
// Ker-Lyon audio courtesy of @adalan, ker-lyon.fr // Ker-Lyon audio courtesy of @adalan, ker-lyon.fr
const audioElement = new Audio('/static/song/konami.ogg') const audioElement = new Audio('/static/song/konami.ogg')
audioElement.loop = true audioElement.loop = true
@ -25,21 +25,21 @@ function afterKonami() {
max: 1.1 max: 1.1
}) })
rythm.addRythm('d-flex', 'color', 50, 50, { rythm.addRythm('d-flex', 'color', 50, 50, {
from: [64,64,64], from: [64, 64, 64],
to:[128,64,128] to: [128, 64, 128]
}) })
rythm.addRythm('nav-link', 'jump', 150, 50, { rythm.addRythm('nav-link', 'jump', 150, 50, {
min: 0, min: 0,
max: 10 max: 10
}) })
rythm.start() rythm.start()
}); })
} }
// Register custom event // Register custom event
document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
cursor = (e.keyCode == KONAMI_CODE[cursor]) ? cursor + 1 : 0; cursor = (e.keyCode == KONAMI_CODE[cursor]) ? cursor + 1 : 0
if (cursor == KONAMI_CODE.length) { if (cursor == KONAMI_CODE.length) {
afterKonami() afterKonami()
} }
}); })

View File

@ -1,440 +1,422 @@
var LOCK = false; var LOCK = false
sources = []; sources = []
sources_notes_display = []; sources_notes_display = []
dests = []; dests = []
dests_notes_display = []; dests_notes_display = []
function refreshHistory() { function refreshHistory () {
$("#history").load("/note/transfer/ #history"); $('#history').load('/note/transfer/ #history')
} }
function reset(refresh=true) { function reset (refresh = true) {
sources_notes_display.length = 0; sources_notes_display.length = 0
sources.length = 0; sources.length = 0
dests_notes_display.length = 0; dests_notes_display.length = 0
dests.length = 0; dests.length = 0
$("#source_note_list").html(""); $('#source_note_list').html('')
$("#dest_note_list").html(""); $('#dest_note_list').html('')
let source_field = $("#source_note"); const source_field = $('#source_note')
source_field.val(""); source_field.val('')
let event = jQuery.Event("keyup"); const event = jQuery.Event('keyup')
event.originalEvent = {charCode: 97}; event.originalEvent = { charCode: 97 }
source_field.trigger(event); source_field.trigger(event)
source_field.removeClass('is-invalid'); source_field.removeClass('is-invalid')
source_field.attr("data-original-title", "").tooltip("hide"); source_field.attr('data-original-title', '').tooltip('hide')
let dest_field = $("#dest_note"); const dest_field = $('#dest_note')
dest_field.val(""); dest_field.val('')
dest_field.trigger(event); dest_field.trigger(event)
dest_field.removeClass('is-invalid'); dest_field.removeClass('is-invalid')
dest_field.attr("data-original-title", "").tooltip("hide"); dest_field.attr('data-original-title', '').tooltip('hide')
let amount_field = $("#amount"); const amount_field = $('#amount')
amount_field.val(""); amount_field.val('')
amount_field.removeClass('is-invalid'); amount_field.removeClass('is-invalid')
$("#amount-required").html(""); $('#amount-required').html('')
let reason_field = $("#reason"); const reason_field = $('#reason')
reason_field.val(""); reason_field.val('')
reason_field.removeClass('is-invalid'); reason_field.removeClass('is-invalid')
$("#reason-required").html(""); $('#reason-required').html('')
$("#last_name").val(""); $('#last_name').val('')
$("#first_name").val(""); $('#first_name').val('')
$("#bank").val(""); $('#bank').val('')
$("#user_note").val(""); $('#user_note').val('')
$("#profile_pic").attr("src", "/static/member/img/default_picture.png"); $('#profile_pic').attr('src', '/static/member/img/default_picture.png')
$("#profile_pic_link").attr("href", "#"); $('#profile_pic_link').attr('href', '#')
if (refresh) { if (refresh) {
refreshBalance(); refreshBalance()
refreshHistory(); refreshHistory()
} }
LOCK = false; LOCK = false
} }
$(document).ready(function() { $(document).ready(function () {
/** /**
* If we are in credit/debit mode, check that only one note is entered. * If we are in credit/debit mode, check that only one note is entered.
* More over, get first name and last name to autocomplete fields. * More over, get first name and last name to autocomplete fields.
*/ */
function checkUniqueNote() { function checkUniqueNote () {
if ($("#type_credit").is(":checked") || $("#type_debit").is(":checked")) { if ($('#type_credit').is(':checked') || $('#type_debit').is(':checked')) {
let arr = $("#type_credit").is(":checked") ? dests_notes_display : sources_notes_display; const arr = $('#type_credit').is(':checked') ? dests_notes_display : sources_notes_display
if (arr.length === 0) if (arr.length === 0) { return }
return;
let last = arr[arr.length - 1]; const last = arr[arr.length - 1]
arr.length = 0; arr.length = 0
arr.push(last); arr.push(last)
last.quantity = 1; last.quantity = 1
if (!last.note.user) { if (!last.note.user) {
$.getJSON("/api/note/note/" + last.note.id + "/?format=json", function(note) { $.getJSON('/api/note/note/' + last.note.id + '/?format=json', function (note) {
last.note.user = note.user; last.note.user = note.user
$.getJSON("/api/user/" + last.note.user + "/", function(user) { $.getJSON('/api/user/' + last.note.user + '/', function (user) {
$("#last_name").val(user.last_name); $('#last_name').val(user.last_name)
$("#first_name").val(user.first_name); $('#first_name').val(user.first_name)
}); })
}); })
} } else {
else { $.getJSON('/api/user/' + last.note.user + '/', function (user) {
$.getJSON("/api/user/" + last.note.user + "/", function(user) { $('#last_name').val(user.last_name)
$("#last_name").val(user.last_name); $('#first_name').val(user.first_name)
$("#first_name").val(user.first_name); })
});
} }
} }
return true; return true
} }
autoCompleteNote("source_note", "source_note_list", sources, sources_notes_display, autoCompleteNote('source_note', 'source_note_list', sources, sources_notes_display,
"source_alias", "source_note", "user_note", "profile_pic", checkUniqueNote); 'source_alias', 'source_note', 'user_note', 'profile_pic', checkUniqueNote)
autoCompleteNote("dest_note", "dest_note_list", dests, dests_notes_display, autoCompleteNote('dest_note', 'dest_note_list', dests, dests_notes_display,
"dest_alias", "dest_note", "user_note", "profile_pic", checkUniqueNote); 'dest_alias', 'dest_note', 'user_note', 'profile_pic', checkUniqueNote)
let source = $("#source_note"); const source = $('#source_note')
let dest = $("#dest_note"); const dest = $('#dest_note')
$("#type_transfer").change(function() { $('#type_transfer').change(function () {
if (LOCK) if (LOCK) { return }
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')
$("#special_transaction_div").addClass('d-none'); $('#special_transaction_div').addClass('d-none')
source.removeClass('d-none'); source.removeClass('d-none')
$("#source_note_list").removeClass('d-none'); $('#source_note_list').removeClass('d-none')
$("#credit_type").addClass('d-none'); $('#credit_type').addClass('d-none')
dest.removeClass('d-none'); dest.removeClass('d-none')
$("#dest_note_list").removeClass('d-none'); $('#dest_note_list').removeClass('d-none')
$("#debit_type").addClass('d-none'); $('#debit_type').addClass('d-none')
$("#source_note_label").text(select_emitters_label); $('#source_note_label').text(select_emitters_label)
$("#dest_note_label").text(select_receveirs_label); $('#dest_note_label').text(select_receveirs_label)
location.hash = "transfer"; location.hash = 'transfer'
}); })
$("#type_credit").change(function() { $('#type_credit').change(function () {
if (LOCK) if (LOCK) { return }
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')
$("#special_transaction_div").removeClass('d-none'); $('#special_transaction_div').removeClass('d-none')
$("#source_note_list").addClass('d-none'); $('#source_note_list').addClass('d-none')
$("#dest_note_list").removeClass('d-none'); $('#dest_note_list').removeClass('d-none')
source.addClass('d-none'); source.addClass('d-none')
source.tooltip('hide'); source.tooltip('hide')
$("#credit_type").removeClass('d-none'); $('#credit_type').removeClass('d-none')
dest.removeClass('d-none'); dest.removeClass('d-none')
dest.val(''); dest.val('')
dest.tooltip('hide'); dest.tooltip('hide')
$("#debit_type").addClass('d-none'); $('#debit_type').addClass('d-none')
$("#source_note_label").text(transfer_type_label); $('#source_note_label').text(transfer_type_label)
$("#dest_note_label").text(select_receveir_label); $('#dest_note_label').text(select_receveir_label)
if (dests_notes_display.length > 1) { if (dests_notes_display.length > 1) {
$("#dest_note_list").html(''); $('#dest_note_list').html('')
dests_notes_display.length = 0; dests_notes_display.length = 0
} }
location.hash = "credit"; location.hash = 'credit'
}); })
$("#type_debit").change(function() { $('#type_debit').change(function () {
if (LOCK) if (LOCK) { return }
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')
$("#special_transaction_div").removeClass('d-none'); $('#special_transaction_div').removeClass('d-none')
$("#source_note_list").removeClass('d-none'); $('#source_note_list').removeClass('d-none')
$("#dest_note_list").addClass('d-none'); $('#dest_note_list').addClass('d-none')
source.removeClass('d-none'); source.removeClass('d-none')
source.val(''); source.val('')
source.tooltip('hide'); source.tooltip('hide')
$("#credit_type").addClass('d-none'); $('#credit_type').addClass('d-none')
dest.addClass('d-none'); dest.addClass('d-none')
dest.tooltip('hide'); dest.tooltip('hide')
$("#debit_type").removeClass('d-none'); $('#debit_type').removeClass('d-none')
$("#source_note_label").text(select_emitter_label); $('#source_note_label').text(select_emitter_label)
$("#dest_note_label").text(transfer_type_label); $('#dest_note_label').text(transfer_type_label)
if (sources_notes_display.length > 1) { if (sources_notes_display.length > 1) {
$("#source_note_list").html(''); $('#source_note_list').html('')
sources_notes_display.length = 0; sources_notes_display.length = 0
} }
location.hash = "debit"; location.hash = 'debit'
}); })
$("#credit_type").change(function() { $('#credit_type').change(function () {
let type = $("#credit_type option:selected").text(); const type = $('#credit_type option:selected').text()
if ($("#type_credit").is(":checked")) if ($('#type_credit').is(':checked')) { source.val(type) } else { dest.val(type) }
source.val(type); })
else
dest.val(type);
});
// Ensure we begin in transfer mode. Removing these lines may cause problems when reloading. // Ensure we begin in transfer mode. Removing these lines may cause problems when reloading.
let type_transfer = $("#type_transfer"); // Default mode const type_transfer = $('#type_transfer') // Default mode
type_transfer.removeAttr('checked'); type_transfer.removeAttr('checked')
$("#type_credit").removeAttr('checked'); $('#type_credit').removeAttr('checked')
$("#type_debit").removeAttr('checked'); $('#type_debit').removeAttr('checked')
if (location.hash) if (location.hash) { $('#type_' + location.hash.substr(1)).click() } else { type_transfer.click() }
$("#type_" + location.hash.substr(1)).click();
else
type_transfer.click();
$("#source_me").click(function() { $('#source_me').click(function () {
if (LOCK) if (LOCK) { return }
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
$("#source_note_list").html(""); $('#source_note_list').html('')
let source_note = $("#source_note"); const source_note = $('#source_note')
source_note.focus(); source_note.focus()
source_note.val(""); source_note.val('')
let event = jQuery.Event("keyup"); let event = jQuery.Event('keyup')
event.originalEvent = {charCode: 97}; event.originalEvent = { charCode: 97 }
source_note.trigger(event); source_note.trigger(event)
source_note.val(username); source_note.val(username)
event = jQuery.Event("keyup"); event = jQuery.Event('keyup')
event.originalEvent = {charCode: 97}; event.originalEvent = { charCode: 97 }
source_note.trigger(event); source_note.trigger(event)
let fill_note = function() { const fill_note = function () {
if (sources.length === 0) { if (sources.length === 0) {
setTimeout(fill_note, 100); setTimeout(fill_note, 100)
return; return
} }
event = jQuery.Event("keypress"); event = jQuery.Event('keypress')
event.originalEvent = {charCode: 13}; event.originalEvent = { charCode: 13 }
source_note.trigger(event); source_note.trigger(event)
source_note.tooltip('hide'); source_note.tooltip('hide')
source_note.val(''); source_note.val('')
$("#dest_note").focus(); $('#dest_note').focus()
}; }
fill_note(); fill_note()
}); })
}); })
$("#btn_transfer").click(function() { $('#btn_transfer').click(function () {
if (LOCK) if (LOCK) { return }
return;
LOCK = true; LOCK = true
let error = false; let error = false
let amount_field = $("#amount"); const amount_field = $('#amount')
amount_field.removeClass('is-invalid'); amount_field.removeClass('is-invalid')
$("#amount-required").html(""); $('#amount-required').html('')
let reason_field = $("#reason"); const reason_field = $('#reason')
reason_field.removeClass('is-invalid'); reason_field.removeClass('is-invalid')
$("#reason-required").html(""); $('#reason-required').html('')
if (!amount_field.val() || isNaN(amount_field.val()) || amount_field.val() <= 0) { if (!amount_field.val() || isNaN(amount_field.val()) || amount_field.val() <= 0) {
amount_field.addClass('is-invalid'); amount_field.addClass('is-invalid')
$("#amount-required").html("<strong>Ce champ est requis et doit comporter un nombre décimal strictement positif.</strong>"); $('#amount-required').html('<strong>Ce champ est requis et doit comporter un nombre décimal strictement positif.</strong>')
error = true; error = true
} }
let amount = Math.floor(100 * amount_field.val()); const amount = Math.floor(100 * amount_field.val())
if (amount > 2147483647) { if (amount > 2147483647) {
amount_field.addClass('is-invalid'); amount_field.addClass('is-invalid')
$("#amount-required").html("<strong>Le montant ne doit pas excéder 21474836.47 €.</strong>"); $('#amount-required').html('<strong>Le montant ne doit pas excéder 21474836.47 €.</strong>')
error = true; error = true
} }
if (!reason_field.val()) { if (!reason_field.val()) {
reason_field.addClass('is-invalid'); reason_field.addClass('is-invalid')
$("#reason-required").html("<strong>Ce champ est requis.</strong>"); $('#reason-required').html('<strong>Ce champ est requis.</strong>')
error = true; error = true
} }
if (!sources_notes_display.length && !$("#type_credit").is(':checked')) { if (!sources_notes_display.length && !$('#type_credit').is(':checked')) {
$("#source_note").addClass('is-invalid'); $('#source_note').addClass('is-invalid')
error = true; error = true
} }
if (!dests_notes_display.length && !$("#type_debit").is(':checked')) { if (!dests_notes_display.length && !$('#type_debit').is(':checked')) {
$("#dest_note").addClass('is-invalid'); $('#dest_note').addClass('is-invalid')
error = true; error = true
} }
if (error) { if (error) {
LOCK = false; LOCK = false
return; return
} }
let reason = reason_field.val(); let reason = reason_field.val()
if ($("#type_transfer").is(':checked')) { if ($('#type_transfer').is(':checked')) {
// We copy the arrays to ensure that transactions are well-processed even if the form is reset // We copy the arrays to ensure that transactions are well-processed even if the form is reset
[...sources_notes_display].forEach(function (source) { [...sources_notes_display].forEach(function (source) {
[...dests_notes_display].forEach(function (dest) { [...dests_notes_display].forEach(function (dest) {
if (source.note.id === dest.note.id) { if (source.note.id === dest.note.id) {
addMsg("Attention : la transaction de " + pretty_money(amount) + " de la note " + source.name addMsg('Attention : la transaction de ' + pretty_money(amount) + ' de la note ' + source.name +
+ " vers la note " + dest.name + " n'a pas été faite car il s'agit de la même note au départ" + ' vers la note ' + dest.name + " n'a pas été faite car il s'agit de la même note au départ" +
" et à l'arrivée.","warning", 10000); " et à l'arrivée.", 'warning', 10000)
LOCK = false; LOCK = false
return; return
} }
$.post("/api/note/transaction/transaction/", $.post('/api/note/transaction/transaction/',
{ {
"csrfmiddlewaretoken": CSRF_TOKEN, csrfmiddlewaretoken: CSRF_TOKEN,
"quantity": source.quantity * dest.quantity, quantity: source.quantity * dest.quantity,
"amount": amount, amount: amount,
"reason": reason, reason: reason,
"valid": true, valid: true,
"polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE, polymorphic_ctype: TRANSFER_POLYMORPHIC_CTYPE,
"resourcetype": "Transaction", resourcetype: 'Transaction',
"source": source.note.id, source: source.note.id,
"source_alias": source.name, source_alias: source.name,
"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("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)
if (dest.note.membership && dest.note.membership.date_end < new Date().toISOString()) }
addMsg("Attention : la note destination " + dest.name + " n'est plus adhérente.", if (dest.note.membership && dest.note.membership.date_end < new Date().toISOString()) {
"danger", 30000); addMsg('Attention : la note destination ' + dest.name + " n'est plus adhérente.",
'danger', 30000)
}
if (!isNaN(source.note.balance)) { if (!isNaN(source.note.balance)) {
let newBalance = source.note.balance - source.quantity * dest.quantity * amount; const newBalance = source.note.balance - source.quantity * dest.quantity * amount
if (newBalance <= -5000) { if (newBalance <= -5000) {
addMsg("Le transfert de " addMsg('Le transfert de ' +
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " pretty_money(source.quantity * dest.quantity * amount) + ' de la note ' +
+ source.name + " vers la note " + dest.name + " a été fait avec succès, " + source.name + ' vers la note ' + dest.name + ' a été fait avec succès, ' +
"mais la note émettrice est en négatif sévère.", "danger", 10000); 'mais la note émettrice est en négatif sévère.', 'danger', 10000)
reset(); reset()
return; return
} } else if (newBalance < 0) {
else if (newBalance < 0) { addMsg('Le transfert de ' +
addMsg("Le transfert de " pretty_money(source.quantity * dest.quantity * amount) + ' de la note ' +
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " source.name + ' vers la note ' + dest.name + ' a été fait avec succès, ' +
+ source.name + " vers la note " + dest.name + " a été fait avec succès, " + 'mais la note émettrice est en négatif.', 'warning', 10000)
"mais la note émettrice est en négatif.", "warning", 10000); reset()
reset(); return
return;
} }
} }
addMsg("Le transfert de " addMsg('Le transfert de ' +
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name pretty_money(source.quantity * dest.quantity * amount) + ' de la note ' + source.name +
+ " vers la note " + dest.name + " a été fait avec succès !", "success", 10000); ' vers la note ' + dest.name + ' a été fait avec succès !', 'success', 10000)
reset(); reset()
}).fail(function (err) { // do it again but valid = false }).fail(function (err) { // do it again but valid = false
let errObj = JSON.parse(err.responseText); const errObj = JSON.parse(err.responseText)
if (errObj["non_field_errors"]) { if (errObj.non_field_errors) {
addMsg("Le transfert de " addMsg('Le transfert de ' +
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name pretty_money(source.quantity * dest.quantity * amount) + ' de la note ' + source.name +
+ " vers la note " + dest.name + " a échoué : " + errObj["non_field_errors"], "danger"); ' vers la note ' + dest.name + ' a échoué : ' + errObj.non_field_errors, 'danger')
LOCK = false; LOCK = false
return; return
} }
$.post("/api/note/transaction/transaction/", $.post('/api/note/transaction/transaction/',
{ {
"csrfmiddlewaretoken": CSRF_TOKEN, csrfmiddlewaretoken: CSRF_TOKEN,
"quantity": source.quantity * dest.quantity, quantity: source.quantity * dest.quantity,
"amount": amount, amount: amount,
"reason": reason, reason: reason,
"valid": false, valid: false,
"invalidity_reason": "Solde insuffisant", invalidity_reason: 'Solde insuffisant',
"polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE, polymorphic_ctype: TRANSFER_POLYMORPHIC_CTYPE,
"resourcetype": "Transaction", resourcetype: 'Transaction',
"source": source.note.id, source: source.note.id,
"source_alias": source.name, source_alias: source.name,
"destination": dest.note.id, destination: dest.note.id,
"destination_alias": dest.name destination_alias: dest.name
}).done(function () { }).done(function () {
addMsg("Le transfert de " addMsg('Le transfert de ' +
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name pretty_money(source.quantity * dest.quantity * amount) + ' de la note ' + source.name +
+ " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger", 10000); ' vers la note ' + dest.name + ' a échoué : Solde insuffisant', 'danger', 10000)
reset(); reset()
}).fail(function (err) { }).fail(function (err) {
let errObj = JSON.parse(err.responseText); const errObj = JSON.parse(err.responseText)
let error = errObj["detail"] ? errObj["detail"] : errObj["non_field_errors"] let error = errObj.detail ? errObj.detail : errObj.non_field_errors
if (!error) if (!error) { error = err.responseText }
error = err.responseText; addMsg('Le transfert de ' +
addMsg("Le transfert de " pretty_money(source.quantity * dest.quantity * amount) + ' de la note ' + source.name +
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name ' vers la note ' + dest.name + ' a échoué : ' + error, 'danger')
+ " vers la note " + dest.name + " a échoué : " + error, "danger"); LOCK = false
LOCK = false; })
}); })
}); })
}); })
}); } else if ($('#type_credit').is(':checked') || $('#type_debit').is(':checked')) {
} else if ($("#type_credit").is(':checked') || $("#type_debit").is(':checked')) { let special_note
let special_note; let user_note
let user_note; let alias
let alias; const given_reason = reason
let given_reason = reason; let source_id, dest_id
let source_id, dest_id; if ($('#type_credit').is(':checked')) {
if ($("#type_credit").is(':checked')) { special_note = $('#credit_type').val()
special_note = $("#credit_type").val(); user_note = dests_notes_display[0].note
user_note = dests_notes_display[0].note; alias = dests_notes_display[0].name
alias = dests_notes_display[0].name; source_id = special_note
source_id = special_note; dest_id = user_note.id
dest_id = user_note.id; reason = 'Crédit ' + $('#credit_type option:selected').text().toLowerCase()
reason = "Crédit " + $("#credit_type option:selected").text().toLowerCase(); if (given_reason.length > 0) { reason += ' (' + given_reason + ')' }
if (given_reason.length > 0) } else {
reason += " (" + given_reason + ")"; special_note = $('#debit_type').val()
user_note = sources_notes_display[0].note
alias = sources_notes_display[0].name
source_id = user_note.id
dest_id = special_note
reason = 'Retrait ' + $('#credit_type option:selected').text().toLowerCase()
if (given_reason.length > 0) { reason += ' (' + given_reason + ')' }
} }
else { $.post('/api/note/transaction/transaction/',
special_note = $("#debit_type").val();
user_note = sources_notes_display[0].note;
alias = sources_notes_display[0].name;
source_id = user_note.id;
dest_id = special_note;
reason = "Retrait " + $("#credit_type option:selected").text().toLowerCase();
if (given_reason.length > 0)
reason += " (" + given_reason + ")";
}
$.post("/api/note/transaction/transaction/",
{ {
"csrfmiddlewaretoken": CSRF_TOKEN, csrfmiddlewaretoken: CSRF_TOKEN,
"quantity": 1, quantity: 1,
"amount": amount, amount: amount,
"reason": reason, reason: reason,
"valid": true, valid: true,
"polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE, polymorphic_ctype: SPECIAL_TRANSFER_POLYMORPHIC_CTYPE,
"resourcetype": "SpecialTransaction", resourcetype: 'SpecialTransaction',
"source": source_id, source: source_id,
"source_alias": sources_notes_display.length ? alias : null, source_alias: sources_notes_display.length ? alias : null,
"destination": dest_id, destination: dest_id,
"destination_alias": dests_notes_display.length ? alias : null, destination_alias: dests_notes_display.length ? alias : null,
"last_name": $("#last_name").val(), last_name: $('#last_name').val(),
"first_name": $("#first_name").val(), first_name: $('#first_name').val(),
"bank": $("#bank").val() bank: $('#bank').val()
}).done(function () { }).done(function () {
addMsg("Le crédit/retrait a bien été effectué !", "success", 10000); addMsg('Le crédit/retrait a bien été effectué !', 'success', 10000)
if (user_note.membership && user_note.membership.date_end < new Date().toISOString()) if (user_note.membership && user_note.membership.date_end < new Date().toISOString()) { addMsg('Attention : la note ' + alias + " n'est plus adhérente.", 'danger', 10000) }
addMsg("Attention : la note " + alias + " n'est plus adhérente.", "danger", 10000); reset()
reset();
}).fail(function (err) { }).fail(function (err) {
let errObj = JSON.parse(err.responseText); const errObj = JSON.parse(err.responseText)
let error = errObj["detail"] ? errObj["detail"] : errObj["non_field_errors"] let error = errObj.detail ? errObj.detail : errObj.non_field_errors
if (!error) if (!error) { error = err.responseText }
error = err.responseText; addMsg('Le crédit/retrait a échoué : ' + error, 'danger', 10000)
addMsg("Le crédit/retrait a échoué : " + error, "danger", 10000); LOCK = false
LOCK = false; })
});
} }
}); })