Open and validate activities

This commit is contained in:
Yohann D'ANELLO 2020-03-27 22:48:20 +01:00
parent d6e202a26f
commit 8c1d902c30
6 changed files with 121 additions and 18 deletions

View File

@ -4,7 +4,7 @@
from django import forms from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from member.models import Club from member.models import Club
from note.models import NoteUser from note.models import NoteUser, Note
from note_kfet.inputs import DateTimePickerInput, AutocompleteModelSelect from note_kfet.inputs import DateTimePickerInput, AutocompleteModelSelect
from .models import Activity, Guest from .models import Activity, Guest
@ -13,12 +13,19 @@ from .models import Activity, Guest
class ActivityForm(forms.ModelForm): class ActivityForm(forms.ModelForm):
class Meta: class Meta:
model = Activity model = Activity
fields = '__all__' exclude = ('valid', 'open', )
widgets = { widgets = {
"organizer": AutocompleteModelSelect( "organizer": AutocompleteModelSelect(
model=Club, model=Club,
attrs={"api_url": "/api/members/club/"}, attrs={"api_url": "/api/members/club/"},
), ),
"note": AutocompleteModelSelect(
model=Note,
attrs={
"api_url": "/api/note/note/",
'placeholder': 'Note de l\'événement sur laquelle envoyer les crédits d\'invitation ...'
},
),
"attendees_club": AutocompleteModelSelect( "attendees_club": AutocompleteModelSelect(
model=Club, model=Club,
attrs={"api_url": "/api/members/club/"}, attrs={"api_url": "/api/members/club/"},
@ -39,7 +46,7 @@ class GuestForm(forms.ModelForm):
'api_url': '/api/note/note/', 'api_url': '/api/note/note/',
# We don't evaluate the content type at launch because the DB might be not initialized # We don't evaluate the content type at launch because the DB might be not initialized
'api_url_suffix': 'api_url_suffix':
lambda value: '&polymorphic_ctype=' + str(ContentType.objects.get_for_model(NoteUser).pk), lambda: '&polymorphic_ctype=' + str(ContentType.objects.get_for_model(NoteUser).pk),
'placeholder': 'Note ...', 'placeholder': 'Note ...',
}, },
), ),

View File

@ -3,7 +3,7 @@
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from note.models import NoteUser from note.models import NoteUser, Transaction
class ActivityType(models.Model): class ActivityType(models.Model):
@ -44,34 +44,59 @@ class Activity(models.Model):
verbose_name=_('name'), verbose_name=_('name'),
max_length=255, max_length=255,
) )
description = models.TextField( description = models.TextField(
verbose_name=_('description'), verbose_name=_('description'),
) )
activity_type = models.ForeignKey( activity_type = models.ForeignKey(
ActivityType, ActivityType,
on_delete=models.PROTECT, on_delete=models.PROTECT,
related_name='+', related_name='+',
verbose_name=_('type'), verbose_name=_('type'),
) )
organizer = models.ForeignKey( organizer = models.ForeignKey(
'member.Club', 'member.Club',
on_delete=models.PROTECT, on_delete=models.PROTECT,
related_name='+', related_name='+',
verbose_name=_('organizer'), verbose_name=_('organizer'),
) )
note = models.ForeignKey(
'note.Note',
on_delete=models.PROTECT,
related_name='+',
null=True,
blank=True,
verbose_name=_('note'),
)
attendees_club = models.ForeignKey( attendees_club = models.ForeignKey(
'member.Club', 'member.Club',
on_delete=models.PROTECT, on_delete=models.PROTECT,
related_name='+', related_name='+',
verbose_name=_('attendees club'), verbose_name=_('attendees club'),
) )
date_start = models.DateTimeField( date_start = models.DateTimeField(
verbose_name=_('start date'), verbose_name=_('start date'),
) )
date_end = models.DateTimeField( date_end = models.DateTimeField(
verbose_name=_('end date'), verbose_name=_('end date'),
) )
valid = models.BooleanField(
default=False,
verbose_name=_('valid'),
)
open = models.BooleanField(
default=False,
verbose_name=_('open'),
)
class Meta: class Meta:
verbose_name = _("activity") verbose_name = _("activity")
verbose_name_plural = _("activities") verbose_name_plural = _("activities")
@ -122,13 +147,17 @@ class Guest(models.Model):
null=True, null=True,
) )
entry_transaction = models.ForeignKey(
'note.Transaction',
on_delete=models.PROTECT,
blank=True,
null=True,
)
class Meta: class Meta:
verbose_name = _("guest") verbose_name = _("guest")
verbose_name_plural = _("guests") verbose_name_plural = _("guests")
class GuestTransaction(Transaction):
guest = models.OneToOneField(
Guest,
on_delete=models.PROTECT,
)
@property
def type(self):
return _('Invitation')

View File

@ -37,7 +37,7 @@ class TransactionTemplateForm(forms.ModelForm):
'api_url': '/api/note/note/', 'api_url': '/api/note/note/',
# We don't evaluate the content type at launch because the DB might be not initialized # We don't evaluate the content type at launch because the DB might be not initialized
'api_url_suffix': 'api_url_suffix':
lambda value: '&polymorphic_ctype=' + str(ContentType.objects.get_for_model(NoteClub).pk), lambda: '&polymorphic_ctype=' + str(ContentType.objects.get_for_model(NoteClub).pk),
'placeholder': 'Note ...', 'placeholder': 'Note ...',
}, },
), ),

View File

@ -48,9 +48,7 @@ def not_empty_model_change_list(model_name):
return session.get("not_empty_model_change_list_" + model_name) == 1 return session.get("not_empty_model_change_list_" + model_name) == 1
def has_perm(t, obj, field=None): def has_perm(perm, obj):
print(t)
perm = "." + t + ("__" + field if field else "_")
return PermissionBackend().has_perm(get_current_authenticated_user(), perm, obj) return PermissionBackend().has_perm(get_current_authenticated_user(), perm, obj)

View File

@ -28,15 +28,35 @@ function addMsg(msg, alert_type) {
+ msg + "</div>\n"; + msg + "</div>\n";
msgDiv.html(html); msgDiv.html(html);
} }
/** /**
* add Muliple error message from err_obj * add Muliple error message from err_obj
* @param err_obj {error_code:erro_message} * @param errs_obj [{error_code:erro_message}]
*/ */
function errMsg(errs_obj){ function errMsg(errs_obj){
for (const err_msg of Object.values(errs_obj)) { for (const err_msg of Object.values(errs_obj)) {
addMsg(err_msg,'danger'); addMsg(err_msg,'danger');
} }
} }
var reloadWithTurbolinks = (function () {
var scrollPosition;
function reload () {
scrollPosition = [window.scrollX, window.scrollY];
Turbolinks.visit(window.location.toString(), { action: 'replace' })
}
document.addEventListener('turbolinks:load', function () {
if (scrollPosition) {
window.scrollTo.apply(window, scrollPosition);
scrollPosition = null
}
});
return reload;
})();
/** /**
* Reload the balance of the user on the right top corner * Reload the balance of the user on the right top corner
*/ */

View File

@ -7,7 +7,7 @@
{% block content %} {% block content %}
<div class="card bg-light shadow"> <div id="activity_info" class="card bg-light shadow">
<div class="card-header text-center"> <div class="card-header text-center">
<h4>{{ activity.name }}</h4> <h4>{{ activity.name }}</h4>
</div> </div>
@ -38,11 +38,23 @@
<dt class="col-xl-6">{% trans 'guest entry fee'|capfirst %}</dt> <dt class="col-xl-6">{% trans 'guest entry fee'|capfirst %}</dt>
<dd class="col-xl-6">{{ activity.activity_type.guest_entry_fee|pretty_money }}</dd> <dd class="col-xl-6">{{ activity.activity_type.guest_entry_fee|pretty_money }}</dd>
{% endif %} {% endif %}
<dt class="col-xl-6">{% trans 'valid'|capfirst %}</dt>
<dd class="col-xl-6">{{ activity.valid|yesno }}</dd>
<dt class="col-xl-6">{% trans 'opened'|capfirst %}</dt>
<dd class="col-xl-6">{{ activity.open|yesno }}</dd>
</dl> </dl>
</div> </div>
<div class="card-footer text-center"> <div class="card-footer text-center">
{% if "view"|has_perm:activity %} {% if activity.valid and "change__open"|has_perm:activity %}
<a class="btn btn-warning btn-sm my-1" id="open_activity"> {% if activity.open %}{% trans "close"|capfirst %}{% else %}{% trans "open"|capfirst %}{% endif %}</a>
{% endif %}
{% if not activity.open and "change__valid"|has_perm:activity %}
<a class="btn btn-success btn-sm my-1" id="validate_activity"> {% if activity.valid %}{% trans "invalidate"|capfirst %}{% else %}{% trans "validate"|capfirst %}{% endif %}</a>
{% endif %}
{% if "view_"|has_perm:activity %}
<a class="btn btn-primary btn-sm my-1" href="{% url 'activity:activity_update' pk=activity.pk %}"> {% trans "edit"|capfirst %}</a> <a class="btn btn-primary btn-sm my-1" href="{% url 'activity:activity_update' pk=activity.pk %}"> {% trans "edit"|capfirst %}</a>
{% endif %} {% endif %}
{% if activity.activity_type.can_invite %} {% if activity.activity_type.can_invite %}
@ -77,5 +89,42 @@
errMsg(xhr.responseJSON); errMsg(xhr.responseJSON);
}); });
} }
$("#open_activity").click(function() {
$.ajax({
url: "/api/activity/activity/{{ activity.pk }}/",
type: "PATCH",
dataType: "json",
headers: {
"X-CSRFTOKEN": CSRF_TOKEN
},
data: {
open: {{ activity.open|yesno:'false,true' }}
}
}).done(function () {
reloadWithTurbolinks();
}).fail(function (xhr) {
errMsg(xhr.responseJSON);
});
});
$("#validate_activity").click(function () {
console.log(42);
$.ajax({
url: "/api/activity/activity/{{ activity.pk }}/",
type: "PATCH",
dataType: "json",
headers: {
"X-CSRFTOKEN": CSRF_TOKEN
},
data: {
valid: {{ activity.valid|yesno:'false,true' }}
}
}).done(function () {
reloadWithTurbolinks();
}).fail(function (xhr) {
errMsg(xhr.responseJSON);
});
});
</script> </script>
{% endblock %} {% endblock %}