forked from DGNum/gestioCOF
initial
This commit is contained in:
parent
a2177155a0
commit
43d938edd0
20 changed files with 1053 additions and 0 deletions
|
@ -50,6 +50,7 @@ INSTALLED_APPS = (
|
||||||
'django_cas_ng',
|
'django_cas_ng',
|
||||||
'debug_toolbar',
|
'debug_toolbar',
|
||||||
'bootstrapform',
|
'bootstrapform',
|
||||||
|
'kfet',
|
||||||
)
|
)
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
MIDDLEWARE_CLASSES = (
|
||||||
|
|
|
@ -78,6 +78,7 @@ urlpatterns = [
|
||||||
url(r'^utile_bda/bda_diff$', gestioncof_views.liste_bdadiff),
|
url(r'^utile_bda/bda_diff$', gestioncof_views.liste_bdadiff),
|
||||||
url(r'^utile_cof/diff_cof$', gestioncof_views.liste_diffcof),
|
url(r'^utile_cof/diff_cof$', gestioncof_views.liste_diffcof),
|
||||||
url(r'^utile_bda/bda_revente$', gestioncof_views.liste_bdarevente),
|
url(r'^utile_bda/bda_revente$', gestioncof_views.liste_bdarevente),
|
||||||
|
url(r'^k-fet/', include('kfet.urls'))
|
||||||
] + \
|
] + \
|
||||||
(static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
(static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
if settings.DEBUG
|
if settings.DEBUG
|
||||||
|
|
0
kfet/__init__.py
Normal file
0
kfet/__init__.py
Normal file
3
kfet/admin.py
Normal file
3
kfet/admin.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
52
kfet/autocomplete.py
Normal file
52
kfet/autocomplete.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.http import Http404
|
||||||
|
from django.db.models import Q
|
||||||
|
from gestioncof.models import User, Clipper
|
||||||
|
|
||||||
|
def account_new(request):
|
||||||
|
if "q" not in request.GET:
|
||||||
|
raise Http404
|
||||||
|
q = request.GET.get("q")
|
||||||
|
|
||||||
|
if (len(q) == 0):
|
||||||
|
return render(request, "kfet/account_new_autocomplete.html")
|
||||||
|
|
||||||
|
data = {'q': q}
|
||||||
|
|
||||||
|
queries = {}
|
||||||
|
search_words = q.split()
|
||||||
|
|
||||||
|
queries['users_cof'] = User.objects.filter(Q(profile__is_cof = True))
|
||||||
|
queries['users_notcof'] = User.objects.filter(Q(profile__is_cof = False))
|
||||||
|
queries['clippers'] = Clipper.objects
|
||||||
|
|
||||||
|
for word in search_words:
|
||||||
|
queries['users_cof'] = queries['users_cof'].filter(
|
||||||
|
Q(username__icontains = word)
|
||||||
|
| Q(first_name__icontains = word)
|
||||||
|
| Q(last_name__icontains = word))
|
||||||
|
queries['users_notcof'] = queries['users_notcof'].filter(
|
||||||
|
Q(username__icontains = word)
|
||||||
|
| Q(first_name__icontains = word)
|
||||||
|
| Q(last_name__icontains = word))
|
||||||
|
queries['clippers'] = queries['clippers'].filter(
|
||||||
|
Q(username__icontains = word)
|
||||||
|
| Q(fullname__icontains = word))
|
||||||
|
|
||||||
|
queries['users_cof'] = queries['users_cof'].distinct()
|
||||||
|
queries['users_notcof'] = queries['users_notcof'].distinct()
|
||||||
|
|
||||||
|
usernames = list(queries['users_cof'].values_list('username', flat=True))
|
||||||
|
usernames += list(queries['users_notcof'] \
|
||||||
|
.values_list('username', flat=True))
|
||||||
|
queries['clippers'] = \
|
||||||
|
queries['clippers'].exclude(username__in=usernames).distinct()
|
||||||
|
|
||||||
|
data.update(queries)
|
||||||
|
|
||||||
|
options = 0
|
||||||
|
for query in queries.values():
|
||||||
|
options += len(query)
|
||||||
|
data['options'] = options
|
||||||
|
|
||||||
|
return render(request, "kfet/account_new_autocomplete.html", data)
|
36
kfet/forms.py
Normal file
36
kfet/forms.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
from django import forms
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from kfet.models import Account
|
||||||
|
from gestioncof.models import CofProfile
|
||||||
|
|
||||||
|
class AccountTrigrammeForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Account
|
||||||
|
fields = ['trigramme']
|
||||||
|
widgets = {
|
||||||
|
'trigramme': forms.TextInput(attrs={'autocomplete': 'off'}),
|
||||||
|
}
|
||||||
|
|
||||||
|
class AccountForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Account
|
||||||
|
fields = ['promo', 'nickname']
|
||||||
|
|
||||||
|
class CofForm(forms.ModelForm):
|
||||||
|
def clean_is_cof(self):
|
||||||
|
instance = getattr(self, 'instance', None)
|
||||||
|
if instance and instance.pk:
|
||||||
|
return instance.is_cof
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
class Meta:
|
||||||
|
model = CofProfile
|
||||||
|
fields = ['login_clipper', 'is_cof', 'departement']
|
||||||
|
|
||||||
|
class UserForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = ['username', 'first_name', 'last_name', 'email']
|
||||||
|
help_texts = {
|
||||||
|
'username': ''
|
||||||
|
}
|
257
kfet/migrations/0001_initial.py
Normal file
257
kfet/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.core.validators
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('gestioncof', '0007_auto_20160802_1022'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Account',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('trigramme', models.CharField(max_length=3, validators=[django.core.validators.RegexValidator(regex='^[^a-z]{3}$')], unique=True)),
|
||||||
|
('balance', models.DecimalField(decimal_places=2, default=0, max_digits=6)),
|
||||||
|
('frozen', models.BooleanField(default=False)),
|
||||||
|
('promo', models.IntegerField(null=True, blank=True, choices=[(1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016)], default=2015)),
|
||||||
|
('nickname', models.CharField(max_length=255, blank=True, default='')),
|
||||||
|
('password', models.CharField(max_length=255, blank=True, null=True, unique=True, default=None)),
|
||||||
|
('cofprofile', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='account_kfet', to='gestioncof.CofProfile')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='AccountNegative',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('start', models.DateTimeField(default=datetime.datetime(2016, 8, 2, 10, 22, 1, 569492))),
|
||||||
|
('balance_offset', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('authorized_overdraft', models.DecimalField(decimal_places=2, default=0, max_digits=6)),
|
||||||
|
('comment', models.CharField(max_length=255, blank=True)),
|
||||||
|
('account', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='negative', to='kfet.Account')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Article',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=45)),
|
||||||
|
('is_sold', models.BooleanField(default=True)),
|
||||||
|
('price', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('stock', models.IntegerField(default=0)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ArticleCategory',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=45)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ArticleRule',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('ratio', models.PositiveSmallIntegerField()),
|
||||||
|
('article_on', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='rule_on', to='kfet.Article')),
|
||||||
|
('article_to', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='rule_to', to='kfet.Article')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Checkout',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=45)),
|
||||||
|
('valid_from', models.DateTimeField()),
|
||||||
|
('valid_to', models.DateTimeField()),
|
||||||
|
('balance', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('is_protected', models.BooleanField(default=False)),
|
||||||
|
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='kfet.Account')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CheckoutTransfer',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('amount', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('from_checkout', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transfers_from', to='kfet.Checkout')),
|
||||||
|
('to_checkout', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transfers_to', to='kfet.Checkout')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Inventory',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='InventoryArticle',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('stock_old', models.IntegerField()),
|
||||||
|
('stock_new', models.IntegerField()),
|
||||||
|
('stock_error', models.IntegerField(default=0)),
|
||||||
|
('article', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Article')),
|
||||||
|
('inventory', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Inventory')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Operation',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('type', models.CharField(max_length=8, choices=[('purchase', 'Achat'), ('deposit', 'Charge'), ('withdraw', 'Retrait')])),
|
||||||
|
('amount', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('on_checkout', models.BooleanField(default=True)),
|
||||||
|
('canceled_at', models.DateTimeField(blank=True, null=True, default=None)),
|
||||||
|
('addcost_amount', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('addcost_for', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='addcosts', to='kfet.Account', null=True, default=None)),
|
||||||
|
('article', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='operations', to='kfet.Article', null=True, default=None)),
|
||||||
|
('canceled_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='+', to='kfet.Account', null=True, default=None)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='OperationGroup',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('amount', models.IntegerField()),
|
||||||
|
('is_cof', models.BooleanField(default=False)),
|
||||||
|
('comment', models.CharField(max_length=255, blank=True, default='')),
|
||||||
|
('checkout', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='operations', to='kfet.Checkout')),
|
||||||
|
('on_acc', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='operations', to='kfet.Account')),
|
||||||
|
('valid_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='+', to='kfet.Account', null=True, default=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Order',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('amount', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='OrderArticle',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('quantity_ordered', models.IntegerField()),
|
||||||
|
('quantity_received', models.IntegerField()),
|
||||||
|
('article', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Article')),
|
||||||
|
('order', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Order')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Statement',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('balance_old', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('balance_new', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('amount_taken', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('amount_error', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='kfet.Account')),
|
||||||
|
('checkout', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='statements', to='kfet.Checkout')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Supplier',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=45)),
|
||||||
|
('address', models.TextField()),
|
||||||
|
('email', models.EmailField(max_length=254)),
|
||||||
|
('phone', models.CharField(max_length=10)),
|
||||||
|
('comment', models.TextField()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SupplierArticle',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('box_type', models.CharField(max_length=7, choices=[('caisse', 'Caisse'), ('carton', 'Carton'), ('palette', 'Palette'), ('fût', 'Fût')])),
|
||||||
|
('box_capacity', models.PositiveSmallIntegerField()),
|
||||||
|
('price_HT', models.DecimalField(decimal_places=4, max_digits=7)),
|
||||||
|
('TVA', models.DecimalField(decimal_places=2, max_digits=4)),
|
||||||
|
('rights', models.DecimalField(decimal_places=4, max_digits=7)),
|
||||||
|
('article', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Article')),
|
||||||
|
('supplier', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kfet.Supplier')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Transfer',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('amount', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||||
|
('canceled_at', models.DateTimeField(blank=True, null=True, default=None)),
|
||||||
|
('canceled_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='+', to='kfet.Account', null=True, default=None)),
|
||||||
|
('from_acc', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transfers_from', to='kfet.Account')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TransferGroup',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('comment', models.CharField(max_length=255, blank=True, default='')),
|
||||||
|
('valid_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='+', to='kfet.Account', null=True, default=None)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='transfer',
|
||||||
|
name='group',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transfers', to='kfet.TransferGroup'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='transfer',
|
||||||
|
name='to_acc',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transfers_to', to='kfet.Account'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='supplier',
|
||||||
|
name='articles',
|
||||||
|
field=models.ManyToManyField(related_name='suppliers', through='kfet.SupplierArticle', to='kfet.Article'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='articles',
|
||||||
|
field=models.ManyToManyField(related_name='orders', through='kfet.OrderArticle', to='kfet.Article'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='supplier',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='orders', to='kfet.Supplier'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='operation',
|
||||||
|
name='group',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='kfet.OperationGroup'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='inventory',
|
||||||
|
name='articles',
|
||||||
|
field=models.ManyToManyField(related_name='inventories', through='kfet.InventoryArticle', to='kfet.Article'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='inventory',
|
||||||
|
name='by',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='kfet.Account'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='inventory',
|
||||||
|
name='order',
|
||||||
|
field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, blank=True, related_name='inventory', to='kfet.Order', null=True, default=None),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='article',
|
||||||
|
name='category',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='articles', to='kfet.ArticleCategory'),
|
||||||
|
),
|
||||||
|
]
|
0
kfet/migrations/__init__.py
Normal file
0
kfet/migrations/__init__.py
Normal file
348
kfet/models.py
Normal file
348
kfet/models.py
Normal file
|
@ -0,0 +1,348 @@
|
||||||
|
from django.db import models
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.core.validators import RegexValidator
|
||||||
|
from gestioncof.models import CofProfile
|
||||||
|
from django.utils.six.moves import reduce
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
def choices_length(choices):
|
||||||
|
return reduce(lambda m, choice: max(m, len(choice[0])), choices, 0)
|
||||||
|
|
||||||
|
def default_promo():
|
||||||
|
now = datetime.date.today()
|
||||||
|
return now.month <= 8 and now.year-1 or now.year
|
||||||
|
|
||||||
|
class Account(models.Model):
|
||||||
|
cofprofile = models.OneToOneField(
|
||||||
|
CofProfile, on_delete = models.PROTECT,
|
||||||
|
related_name = "account_kfet")
|
||||||
|
trigramme = models.CharField(
|
||||||
|
unique = True,
|
||||||
|
max_length = 3,
|
||||||
|
validators = [RegexValidator(regex='^[^a-z]{3}$')])
|
||||||
|
balance = models.DecimalField(
|
||||||
|
max_digits = 6, decimal_places = 2,
|
||||||
|
default = 0)
|
||||||
|
frozen = models.BooleanField(default = False)
|
||||||
|
# Optional
|
||||||
|
PROMO_CHOICES = [(r,r) for r in range(1980, datetime.date.today().year+1)]
|
||||||
|
promo = models.IntegerField(
|
||||||
|
choices = PROMO_CHOICES,
|
||||||
|
blank = True, null = True, default = default_promo())
|
||||||
|
nickname = models.CharField(
|
||||||
|
max_length = 255,
|
||||||
|
blank = True, default = "")
|
||||||
|
password = models.CharField(
|
||||||
|
max_length = 255,
|
||||||
|
unique = True,
|
||||||
|
blank = True, null = True, default = None)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.trigramme
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_free(trigramme):
|
||||||
|
try:
|
||||||
|
account = Account.objects.filter(trigramme=trigramme).get()
|
||||||
|
return False
|
||||||
|
except Account.DoesNotExist:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Méthode save() avec auth +
|
||||||
|
# Args:
|
||||||
|
# - auth_user : request.user
|
||||||
|
# - data : datas pour User et CofProfile
|
||||||
|
# Action:
|
||||||
|
# - Enregistre User, CofProfile à partir de "data"
|
||||||
|
# - Enregistre Account
|
||||||
|
# Permissions
|
||||||
|
# - Edition si request.user:
|
||||||
|
# - modifie son compte (ne peut pas modifier nickname)
|
||||||
|
# ou - a la perm kfet.change_account
|
||||||
|
# - Ajout si request.user a la perm kfet.add_account
|
||||||
|
def save_api(self, auth_user, data = None):
|
||||||
|
if self.pk:
|
||||||
|
# Account update
|
||||||
|
|
||||||
|
# Checking permissions
|
||||||
|
user = self.cofprofile.user
|
||||||
|
if not auth_user.has_perm('kfet.change_account') \
|
||||||
|
and request.user != user:
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
# Updating User with data
|
||||||
|
user.first_name = data.get("first_name", user.first_name)
|
||||||
|
user.last_name = data.get("last_name", user.last_name)
|
||||||
|
user.email = data.get("email", user.email)
|
||||||
|
user.save()
|
||||||
|
# Updating CofProfile with data
|
||||||
|
cof = self.cofprofile
|
||||||
|
cof.departement = data.get("departement", cof.departement)
|
||||||
|
cof.save()
|
||||||
|
# Nickname is not editable by the user
|
||||||
|
if not auth_user.has_perm('kfet.change_account'):
|
||||||
|
account_old = Account.objects.get(pk=self.pk)
|
||||||
|
self.nickname = account_old.nickname
|
||||||
|
else:
|
||||||
|
# New account
|
||||||
|
|
||||||
|
# Checking permissions
|
||||||
|
if not auth_user.has_perm('kfet.add_account'):
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
# Creating or updating User instance
|
||||||
|
username = data.get("username")
|
||||||
|
(user, _) = User.objects.get_or_create(username=username)
|
||||||
|
if "first_name" in data:
|
||||||
|
user.first_name = data['first_name']
|
||||||
|
if "last_name" in data:
|
||||||
|
user.last_name = data['last_name']
|
||||||
|
if "email" in data:
|
||||||
|
user.email = data['email']
|
||||||
|
user.save()
|
||||||
|
# Creating or updating CofProfile instance
|
||||||
|
(cof, _) = CofProfile.objects.get_or_create(user=user)
|
||||||
|
if "login_clipper" in data:
|
||||||
|
cof.login_clipper = data['login_clipper']
|
||||||
|
if "departement" in data:
|
||||||
|
cof.departement = data['departement']
|
||||||
|
cof.save()
|
||||||
|
# Check if cof is linked to an account
|
||||||
|
if hasattr(cof, 'account_kfet'):
|
||||||
|
raise Account.UserHasAccount(cof.account_kfet.trigramme)
|
||||||
|
self.cofprofile = cof
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
# Surcharge de delete
|
||||||
|
# Pas de suppression possible
|
||||||
|
# Cas à régler plus tard
|
||||||
|
def delete(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class UserHasAccount(Exception):
|
||||||
|
def __init__(self, trigramme):
|
||||||
|
self.trigramme = trigramme
|
||||||
|
|
||||||
|
class AccountNegative(models.Model):
|
||||||
|
account = models.OneToOneField(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
related_name = "negative")
|
||||||
|
start = models.DateTimeField(default = datetime.datetime.now())
|
||||||
|
balance_offset = models.DecimalField(max_digits = 6, decimal_places = 2)
|
||||||
|
authorized_overdraft = models.DecimalField(
|
||||||
|
max_digits = 6, decimal_places = 2,
|
||||||
|
default = 0)
|
||||||
|
comment = models.CharField(max_length = 255, blank = True)
|
||||||
|
|
||||||
|
class Checkout(models.Model):
|
||||||
|
created_by = models.ForeignKey(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
related_name = "+")
|
||||||
|
name = models.CharField(max_length = 45)
|
||||||
|
valid_from = models.DateTimeField()
|
||||||
|
valid_to = models.DateTimeField()
|
||||||
|
balance = models.DecimalField(max_digits = 6, decimal_places = 2)
|
||||||
|
is_protected = models.BooleanField(default = False)
|
||||||
|
|
||||||
|
class CheckoutTransfer(models.Model):
|
||||||
|
from_checkout = models.ForeignKey(
|
||||||
|
Checkout, on_delete = models.PROTECT,
|
||||||
|
related_name = "transfers_from")
|
||||||
|
to_checkout = models.ForeignKey(
|
||||||
|
Checkout, on_delete = models.PROTECT,
|
||||||
|
related_name = "transfers_to")
|
||||||
|
amount = models.DecimalField(
|
||||||
|
max_digits = 6, decimal_places = 2)
|
||||||
|
|
||||||
|
class Statement(models.Model):
|
||||||
|
by = models.ForeignKey(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
related_name = "+")
|
||||||
|
checkout = models.ForeignKey(
|
||||||
|
Checkout, on_delete = models.PROTECT,
|
||||||
|
related_name = "statements")
|
||||||
|
balance_old = models.DecimalField(max_digits = 6, decimal_places = 2)
|
||||||
|
balance_new = models.DecimalField(max_digits = 6, decimal_places = 2)
|
||||||
|
amount_taken = models.DecimalField(max_digits = 6, decimal_places = 2)
|
||||||
|
amount_error = models.DecimalField(max_digits = 6, decimal_places = 2)
|
||||||
|
at = models.DateTimeField(auto_now_add = True)
|
||||||
|
|
||||||
|
class ArticleCategory(models.Model):
|
||||||
|
name = models.CharField(max_length = 45)
|
||||||
|
|
||||||
|
class Article(models.Model):
|
||||||
|
name = models.CharField(max_length = 45)
|
||||||
|
is_sold = models.BooleanField(default = True)
|
||||||
|
price = models.DecimalField(max_digits = 6, decimal_places = 2)
|
||||||
|
stock = models.IntegerField(default = 0)
|
||||||
|
category = models.ForeignKey(
|
||||||
|
ArticleCategory, on_delete = models.PROTECT,
|
||||||
|
related_name = "articles")
|
||||||
|
|
||||||
|
class ArticleRule(models.Model):
|
||||||
|
article_on = models.OneToOneField(
|
||||||
|
Article, on_delete = models.PROTECT,
|
||||||
|
related_name = "rule_on")
|
||||||
|
article_to = models.OneToOneField(
|
||||||
|
Article, on_delete = models.PROTECT,
|
||||||
|
related_name = "rule_to")
|
||||||
|
ratio = models.PositiveSmallIntegerField()
|
||||||
|
|
||||||
|
class Inventory(models.Model):
|
||||||
|
articles = models.ManyToManyField(
|
||||||
|
Article,
|
||||||
|
through = 'InventoryArticle',
|
||||||
|
related_name = "inventories")
|
||||||
|
by = models.ForeignKey(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
related_name = "+")
|
||||||
|
at = models.DateTimeField(auto_now_add = True)
|
||||||
|
# Optional
|
||||||
|
order = models.OneToOneField(
|
||||||
|
'Order', on_delete = models.PROTECT,
|
||||||
|
related_name = "inventory",
|
||||||
|
blank = True, null = True, default = None)
|
||||||
|
|
||||||
|
class InventoryArticle(models.Model):
|
||||||
|
inventory = models.ForeignKey(
|
||||||
|
Inventory, on_delete = models.PROTECT)
|
||||||
|
article = models.ForeignKey(
|
||||||
|
Article, on_delete = models.PROTECT)
|
||||||
|
stock_old = models.IntegerField()
|
||||||
|
stock_new = models.IntegerField()
|
||||||
|
stock_error = models.IntegerField(default = 0)
|
||||||
|
|
||||||
|
class Supplier(models.Model):
|
||||||
|
articles = models.ManyToManyField(
|
||||||
|
Article,
|
||||||
|
through = 'SupplierArticle',
|
||||||
|
related_name = "suppliers")
|
||||||
|
name = models.CharField(max_length = 45)
|
||||||
|
address = models.TextField()
|
||||||
|
email = models.EmailField()
|
||||||
|
phone = models.CharField(max_length = 10)
|
||||||
|
comment = models.TextField()
|
||||||
|
|
||||||
|
class SupplierArticle(models.Model):
|
||||||
|
supplier = models.ForeignKey(
|
||||||
|
Supplier, on_delete = models.PROTECT)
|
||||||
|
article = models.ForeignKey(
|
||||||
|
Article, on_delete = models.PROTECT)
|
||||||
|
BOX_TYPE_CHOICES = (
|
||||||
|
("caisse", "Caisse"),
|
||||||
|
("carton", "Carton"),
|
||||||
|
("palette", "Palette"),
|
||||||
|
("fût", "Fût"),
|
||||||
|
)
|
||||||
|
box_type = models.CharField(
|
||||||
|
choices = BOX_TYPE_CHOICES,
|
||||||
|
max_length = choices_length(BOX_TYPE_CHOICES))
|
||||||
|
box_capacity = models.PositiveSmallIntegerField()
|
||||||
|
price_HT = models.DecimalField(max_digits = 7, decimal_places = 4)
|
||||||
|
TVA = models.DecimalField(max_digits = 4, decimal_places = 2)
|
||||||
|
rights = models.DecimalField(max_digits = 7, decimal_places = 4)
|
||||||
|
|
||||||
|
class Order(models.Model):
|
||||||
|
supplier = models.ForeignKey(
|
||||||
|
Supplier, on_delete = models.PROTECT,
|
||||||
|
related_name = "orders")
|
||||||
|
articles = models.ManyToManyField(
|
||||||
|
Article,
|
||||||
|
through = "OrderArticle",
|
||||||
|
related_name = "orders")
|
||||||
|
at = models.DateTimeField(auto_now_add = True)
|
||||||
|
amount = models.DecimalField(max_digits = 6, decimal_places = 2)
|
||||||
|
|
||||||
|
class OrderArticle(models.Model):
|
||||||
|
order = models.ForeignKey(
|
||||||
|
Order, on_delete = models.PROTECT)
|
||||||
|
article = models.ForeignKey(
|
||||||
|
Article, on_delete = models.PROTECT)
|
||||||
|
quantity_ordered = models.IntegerField()
|
||||||
|
quantity_received = models.IntegerField()
|
||||||
|
|
||||||
|
class TransferGroup(models.Model):
|
||||||
|
at = models.DateTimeField(auto_now_add = True)
|
||||||
|
# Optional
|
||||||
|
comment = models.CharField(
|
||||||
|
max_length = 255,
|
||||||
|
blank = True, default = "")
|
||||||
|
valid_by = models.ForeignKey(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
related_name = "+",
|
||||||
|
blank = True, null = True, default = None)
|
||||||
|
|
||||||
|
class Transfer(models.Model):
|
||||||
|
group = models.ForeignKey(
|
||||||
|
TransferGroup, on_delete = models.PROTECT,
|
||||||
|
related_name = "transfers")
|
||||||
|
from_acc = models.ForeignKey(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
related_name = "transfers_from")
|
||||||
|
to_acc = models.ForeignKey(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
related_name = "transfers_to")
|
||||||
|
amount = models.DecimalField(max_digits = 6, decimal_places = 2)
|
||||||
|
# Optional
|
||||||
|
canceled_by = models.ForeignKey(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
null = True, blank = True, default = None,
|
||||||
|
related_name = "+")
|
||||||
|
canceled_at = models.DateTimeField(
|
||||||
|
null = True, blank = True, default = None)
|
||||||
|
|
||||||
|
class OperationGroup(models.Model):
|
||||||
|
on_acc = models.ForeignKey(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
related_name = "operations")
|
||||||
|
checkout = models.ForeignKey(
|
||||||
|
Checkout, on_delete = models.PROTECT,
|
||||||
|
related_name = "operations")
|
||||||
|
at = models.DateTimeField(auto_now_add = True)
|
||||||
|
amount = models.IntegerField()
|
||||||
|
is_cof = models.BooleanField(default = False)
|
||||||
|
# Optional
|
||||||
|
comment = models.CharField(
|
||||||
|
max_length = 255,
|
||||||
|
blank = True, default = "")
|
||||||
|
valid_by = models.ForeignKey(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
related_name = "+",
|
||||||
|
blank = True, null = True, default = True)
|
||||||
|
|
||||||
|
class Operation(models.Model):
|
||||||
|
PURCHASE = 'purchase'
|
||||||
|
DEPOSIT = 'deposit'
|
||||||
|
WITHDRAW = 'withdraw'
|
||||||
|
|
||||||
|
TYPE_ORDER_CHOICES = (
|
||||||
|
(PURCHASE, 'Achat'),
|
||||||
|
(DEPOSIT, 'Charge'),
|
||||||
|
(WITHDRAW, 'Retrait'),
|
||||||
|
)
|
||||||
|
|
||||||
|
group = models.ForeignKey(
|
||||||
|
OperationGroup, on_delete = models.PROTECT,
|
||||||
|
related_name = "+")
|
||||||
|
type = models.CharField(
|
||||||
|
choices = TYPE_ORDER_CHOICES,
|
||||||
|
max_length = choices_length(TYPE_ORDER_CHOICES))
|
||||||
|
amount = models.DecimalField(max_digits = 6, decimal_places = 2)
|
||||||
|
on_checkout = models.BooleanField(default = True)
|
||||||
|
# Optional
|
||||||
|
article = models.ForeignKey(
|
||||||
|
Article, on_delete = models.PROTECT,
|
||||||
|
related_name = "operations",
|
||||||
|
blank = True, null = True, default = None)
|
||||||
|
canceled_by = models.ForeignKey(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
related_name = "+",
|
||||||
|
blank = True, null = True, default = None)
|
||||||
|
canceled_at = models.DateTimeField(
|
||||||
|
blank = True, null = True, default = None)
|
||||||
|
addcost_for = models.ForeignKey(
|
||||||
|
Account, on_delete = models.PROTECT,
|
||||||
|
related_name = "addcosts",
|
||||||
|
blank = True, null = True, default = None)
|
||||||
|
addcost_amount = models.DecimalField(max_digits = 6, decimal_places = 2)
|
74
kfet/templates/kfet/account_new.html
Normal file
74
kfet/templates/kfet/account_new.html
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
{% extends "kfet/base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}Création d'un nouveau compte{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_head %}
|
||||||
|
<script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
|
||||||
|
<script src="{% static "autocomplete_light/autocomplete.js" %}" type="text/javascript"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Création d'un nouveau compte</h1>
|
||||||
|
|
||||||
|
{% if post %}
|
||||||
|
{% if success %}
|
||||||
|
Nouveau compte créé : {{ trigramme }}
|
||||||
|
{% else %}
|
||||||
|
Echec de la création du compte
|
||||||
|
{{ errors }}
|
||||||
|
{% endif %}
|
||||||
|
<hr>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="{% url "kfet.admin.account.new" %}" method="post">
|
||||||
|
{{ account_trigramme_form }}
|
||||||
|
<div id="trigramme_valid"></div><br>
|
||||||
|
<input type="text" name="q" id="search_autocomplete" spellcheck="false" placeholder="Chercher un utilisateur par nom, prénom ou identifiant clipper">
|
||||||
|
<div id="search_results"></div>
|
||||||
|
<div id="form-placeholder"></div>
|
||||||
|
</form>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
// Affichage des résultats d'autocomplétion
|
||||||
|
$('input#search_autocomplete').yourlabsAutocomplete({
|
||||||
|
url: '{% url "kfet.admin.account.new.autocomplete" %}',
|
||||||
|
minimumCharacters: 0,
|
||||||
|
id: 'search_autocomplete',
|
||||||
|
choiceSelector: 'li:has(a)',
|
||||||
|
container: $("#search_results"),
|
||||||
|
box: $("#search_results"),
|
||||||
|
// fixPosition: function() {},
|
||||||
|
});
|
||||||
|
// Chargement du formulaire adapté au choix sélectionné
|
||||||
|
$('input#search_autocomplete').bind(
|
||||||
|
'selectChoice',
|
||||||
|
function(e, choice, autocomplete) {
|
||||||
|
autocomplete.hide();
|
||||||
|
link = choice.find('a:first');
|
||||||
|
if (link.length && link.attr('href') != undefined) {
|
||||||
|
$('#form-placeholder').html("").load(link.attr('href'));
|
||||||
|
//, function() {
|
||||||
|
//$('#form-placeholder').toggle().toggle();
|
||||||
|
//});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Vérification client de la disponibilité du trigramme choisi
|
||||||
|
old_trigramme = "";
|
||||||
|
$('#id_trigramme').keyup(function() {
|
||||||
|
trigramme = $('#id_trigramme').val();
|
||||||
|
if (trigramme.length == 3 && trigramme != old_trigramme) {
|
||||||
|
$.ajax({
|
||||||
|
dataType: "json",
|
||||||
|
url: "{% url "kfet.admin.account.is_free.ajax" %}",
|
||||||
|
data: { trigramme: trigramme },
|
||||||
|
}).done(function(data) {
|
||||||
|
$('#trigramme_valid').text(data['is_free']);
|
||||||
|
old_trigramme = trigramme;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
43
kfet/templates/kfet/account_new_autocomplete.html
Normal file
43
kfet/templates/kfet/account_new_autocomplete.html
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{% load kfet_tags %}
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="{% url "kfet.admin.account.new.empty" %}">
|
||||||
|
Créer un compte
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% if users_cof %}
|
||||||
|
<li>Membres du COF</li>
|
||||||
|
{% for user in users_cof %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url "kfet.admin.account.new.fromuser" user.username %}">
|
||||||
|
{{ user|highlight_user:q }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if users_notcof %}
|
||||||
|
<li>Non-membres du COF</li>
|
||||||
|
{% for user in users_notcof %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url "kfet.admin.account.new.fromuser" user.username %}">
|
||||||
|
{{ user|highlight_user:q }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if clippers %}
|
||||||
|
<li>Utilisateurs clipper</li>
|
||||||
|
{% for clipper in clippers %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url "kfet.admin.account.new.fromclipper" clipper.username %}">
|
||||||
|
{{ clipper|highlight_clipper:q }}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if not q %}
|
||||||
|
<li>Pas de recherche, pas de résultats !</li>
|
||||||
|
{% elif not options %}
|
||||||
|
<li>Aucune correspondance trouvée :-(</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
5
kfet/templates/kfet/account_new_form.html
Normal file
5
kfet/templates/kfet/account_new_form.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ user_form }}
|
||||||
|
{{ cof_form }}
|
||||||
|
{{ account_form }}
|
||||||
|
<input type="submit" value="Enregistrer">
|
30
kfet/templates/kfet/base.html
Normal file
30
kfet/templates/kfet/base.html
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>{% block title %}{% endblock %} | K-Fêt - ENS Ulm</title>
|
||||||
|
|
||||||
|
{% block extra_head %}{% endblock %}
|
||||||
|
|
||||||
|
{# Vieux IE pas comprendre HTML5 #}
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{% url "kfet.views.home" %}">Home</a></li>
|
||||||
|
{% if perms.kfet.add_account %}
|
||||||
|
<li>
|
||||||
|
<a href={% url "kfet.admin.account.new" %}>Créer un compte</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<section id="content">
|
||||||
|
{% block content %}TGTG{% endblock %}
|
||||||
|
</section>
|
||||||
|
{% include "kfet/base_footer.html" %}
|
||||||
|
</body>
|
||||||
|
</html>
|
0
kfet/templates/kfet/base_footer.html
Normal file
0
kfet/templates/kfet/base_footer.html
Normal file
0
kfet/templatetags/__init__.py
Normal file
0
kfet/templatetags/__init__.py
Normal file
28
kfet/templatetags/kfet_tags.py
Normal file
28
kfet/templatetags/kfet_tags.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
from django import template
|
||||||
|
from django.utils.html import escape
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
import re
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
def highlight_text(text, q):
|
||||||
|
q2 = "|".join(q.split())
|
||||||
|
pattern = re.compile(r"(?P<filter>%s)" % q2, re.IGNORECASE)
|
||||||
|
return mark_safe(re.sub(pattern, r"<span class='highlight_autocomplete'>\g<filter></span>", text))
|
||||||
|
|
||||||
|
@register.filter(is_safe=True)
|
||||||
|
def highlight_user(user, q):
|
||||||
|
if user.first_name and user.last_name:
|
||||||
|
text = "%s %s (%s)" % (user.first_name, user.last_name, user.username)
|
||||||
|
else:
|
||||||
|
text = user.username
|
||||||
|
return highlight_text(escape(text), q)
|
||||||
|
|
||||||
|
@register.filter(is_safe=True)
|
||||||
|
def highlight_clipper(clipper, q):
|
||||||
|
if clipper.fullname:
|
||||||
|
text = "%s (%s)" % (clipper.fullname, clipper.username)
|
||||||
|
else:
|
||||||
|
text = clipper.username
|
||||||
|
return highlight_text(escape(text), q)
|
||||||
|
|
3
kfet/tests.py
Normal file
3
kfet/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
21
kfet/urls.py
Normal file
21
kfet/urls.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
from django.conf.urls import url
|
||||||
|
from kfet import views
|
||||||
|
from kfet import autocomplete
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', views.home),
|
||||||
|
# Administration
|
||||||
|
url(r'^admin/account/new$', views.account_new,
|
||||||
|
name = 'kfet.admin.account.new'),
|
||||||
|
url(r'^admin/account/new/user/(?P<username>.+)$', views.account_new_ajax,
|
||||||
|
name = 'kfet.admin.account.new.fromuser'),
|
||||||
|
url(r'^admin/account/new/clipper/(?P<login_clipper>.+)$', views.account_new_ajax,
|
||||||
|
name = 'kfet.admin.account.new.fromclipper'),
|
||||||
|
url(r'^admin/account/new/empty$', views.account_new_ajax,
|
||||||
|
name = 'kfet.admin.account.new.empty'),
|
||||||
|
url(r'^admin/account/is_free$', views.account_is_free_ajax,
|
||||||
|
name = 'kfet.admin.account.is_free.ajax'),
|
||||||
|
# Autocomplete - Nouveau compte
|
||||||
|
url(r'^autocomplete/account_new$', autocomplete.account_new,
|
||||||
|
name = 'kfet.admin.account.new.autocomplete'),
|
||||||
|
]
|
150
kfet/views.py
Normal file
150
kfet/views.py
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
from django.shortcuts import render, get_object_or_404
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.http import HttpResponse, Http404
|
||||||
|
import json
|
||||||
|
from gestioncof.models import CofProfile, Clipper
|
||||||
|
from kfet.models import Account
|
||||||
|
from kfet.forms import AccountTrigrammeForm, AccountForm, CofForm, UserForm
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def home(request):
|
||||||
|
return render(request, "kfet/base.html")
|
||||||
|
|
||||||
|
def put_cleaned_data_in_dict(dict, form):
|
||||||
|
for field in form.cleaned_data:
|
||||||
|
dict[field] = form.cleaned_data[field]
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@permission_required('kfet.add_account')
|
||||||
|
def account_new(request):
|
||||||
|
# A envoyer au template
|
||||||
|
data_template = {
|
||||||
|
'account_trigramme_form': AccountTrigrammeForm(),
|
||||||
|
'post' : False,
|
||||||
|
'success' : False,
|
||||||
|
'trigramme' : '',
|
||||||
|
'errors' : {},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Enregistrement
|
||||||
|
if request.method == "POST":
|
||||||
|
# Pour indiquer la tentative d'enregistrement au template
|
||||||
|
data_template['post'] = True
|
||||||
|
|
||||||
|
# Peuplement des forms
|
||||||
|
username = request.POST.get('username')
|
||||||
|
try:
|
||||||
|
user = User.objects.filter(username=username).get()
|
||||||
|
(cof, _) = CofProfile.objects.get_or_create(user=user)
|
||||||
|
user_form = UserForm(request.POST, instance=user)
|
||||||
|
cof_form = CofForm(request.POST, instance=cof)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
user_form = UserForm(request.POST)
|
||||||
|
cof_form = CofForm(request.POST)
|
||||||
|
trigramme_form = AccountTrigrammeForm(request.POST)
|
||||||
|
account_form = AccountForm(request.POST)
|
||||||
|
# Ajout des erreurs pour le template
|
||||||
|
data_template['errors']['user_form'] = user_form.errors
|
||||||
|
data_template['errors']['cof_form'] = cof_form.errors
|
||||||
|
data_template['errors']['trigramme_form'] = trigramme_form.errors
|
||||||
|
data_template['errors']['account_form'] = account_form.errors
|
||||||
|
|
||||||
|
if all((user_form.is_valid(), cof_form.is_valid(),
|
||||||
|
trigramme_form.is_valid(), account_form.is_valid())):
|
||||||
|
print(user_form.cleaned_data)
|
||||||
|
data = {}
|
||||||
|
# Fill data
|
||||||
|
put_cleaned_data_in_dict(data, user_form)
|
||||||
|
put_cleaned_data_in_dict(data, cof_form)
|
||||||
|
|
||||||
|
account = Account()
|
||||||
|
account.trigramme = trigramme_form.cleaned_data['trigramme']
|
||||||
|
account.promo = account_form.cleaned_data['promo']
|
||||||
|
account.nickname = account_form.cleaned_data['nickname']
|
||||||
|
try:
|
||||||
|
account.save_api(auth_user = request.user, data = data)
|
||||||
|
data_template['success'] = True
|
||||||
|
data_template['trigramme'] = account.trigramme
|
||||||
|
except Account.UserHasAccount as e:
|
||||||
|
data_template['errors']['global'] = \
|
||||||
|
"Cet utilisateur a déjà un compte K-Fêt : " + e.trigramme
|
||||||
|
except PermissionDenied:
|
||||||
|
print("perm")
|
||||||
|
|
||||||
|
return render(request, "kfet/account_new.html", data_template)
|
||||||
|
|
||||||
|
def account_new_set_readonly_fields(user_form, cof_form):
|
||||||
|
user_form.fields['username'].widget.attrs['readonly'] = True
|
||||||
|
cof_form.fields['login_clipper'].widget.attrs['readonly'] = True
|
||||||
|
cof_form.fields['is_cof'].widget.attrs['disabled'] = True
|
||||||
|
|
||||||
|
def account_new_ajax(request, username=None, login_clipper=None):
|
||||||
|
user = None
|
||||||
|
if login_clipper:
|
||||||
|
# à partir d'un clipper
|
||||||
|
# le user associé à ce clipper ne devrait pas encore existé
|
||||||
|
clipper = get_object_or_404(Clipper, username = login_clipper)
|
||||||
|
try:
|
||||||
|
# Vérification que clipper ne soit pas déjà dans User
|
||||||
|
user = User.objects.filter(username=login_clipper).get()
|
||||||
|
# Ici, on nous a menti, le user existe déjà
|
||||||
|
username = user.username
|
||||||
|
login_clipper = None
|
||||||
|
except User.DoesNotExist:
|
||||||
|
# Clipper (sans user déjà existant)
|
||||||
|
|
||||||
|
# UserForm - Prefill + Création
|
||||||
|
user_initial_data = {
|
||||||
|
'username' : login_clipper,
|
||||||
|
'email' : login_clipper + "@clipper.ens.fr"}
|
||||||
|
if clipper.fullname:
|
||||||
|
# Prefill du nom et prénom
|
||||||
|
names = clipper.fullname.split()
|
||||||
|
# Le premier, c'est le prénom
|
||||||
|
user_initial_data['first_name'] = names[0]
|
||||||
|
if len(names) > 1:
|
||||||
|
# Si d'autres noms -> tous dans le nom de famille
|
||||||
|
user_initial_data['last_name'] = " ".join(names[1:])
|
||||||
|
user_form = UserForm(initial = user_initial_data)
|
||||||
|
|
||||||
|
# CofForm - Prefill + Création
|
||||||
|
cof_initial_data = { 'login_clipper': login_clipper }
|
||||||
|
cof_form = CofForm(initial = cof_initial_data)
|
||||||
|
|
||||||
|
# AccountForm
|
||||||
|
account_form = AccountForm()
|
||||||
|
|
||||||
|
# Protection (read-only) des champs username et login_clipper
|
||||||
|
account_new_set_readonly_fields(user_form, cof_form)
|
||||||
|
if username:
|
||||||
|
# le user existe déjà
|
||||||
|
user = get_object_or_404(User, username=username)
|
||||||
|
# récupération du profil cof
|
||||||
|
(cof, _) = CofProfile.objects.get_or_create(user=user)
|
||||||
|
# UserForm + CofForm - Création à partir des instances existantes
|
||||||
|
user_form = UserForm(instance = user)
|
||||||
|
cof_form = CofForm(instance = cof)
|
||||||
|
# AccountForm
|
||||||
|
account_form = AccountForm()
|
||||||
|
# Protection (read-only) des champs username et login_clipper
|
||||||
|
account_new_set_readonly_fields(user_form, cof_form)
|
||||||
|
elif not login_clipper:
|
||||||
|
# connaît pas du tout, faut tout remplir
|
||||||
|
user_form = UserForm()
|
||||||
|
cof_form = CofForm()
|
||||||
|
account_form = AccountForm()
|
||||||
|
|
||||||
|
return render(request, "kfet/account_new_form.html", {
|
||||||
|
'account_form' : account_form,
|
||||||
|
'cof_form' : cof_form,
|
||||||
|
'user_form' : user_form,
|
||||||
|
})
|
||||||
|
|
||||||
|
def account_is_free_ajax(request):
|
||||||
|
if not request.GET.get("trigramme"):
|
||||||
|
raise Http404
|
||||||
|
trigramme = request.GET.get("trigramme")
|
||||||
|
data = { 'is_free': Account.is_free(trigramme) }
|
||||||
|
return HttpResponse(json.dumps(data), content_type = 'application/json')
|
|
@ -12,3 +12,4 @@ six==1.10.0
|
||||||
unicodecsv==0.14.1
|
unicodecsv==0.14.1
|
||||||
icalendar==3.10
|
icalendar==3.10
|
||||||
django-bootstrap-form==3.2.1
|
django-bootstrap-form==3.2.1
|
||||||
|
django-rest-framework==3.4.0
|
||||||
|
|
Loading…
Reference in a new issue