diff --git a/cof/settings_dev.py b/cof/settings_dev.py index ee777e1c..ad2b0b64 100644 --- a/cof/settings_dev.py +++ b/cof/settings_dev.py @@ -50,6 +50,7 @@ INSTALLED_APPS = ( 'django_cas_ng', 'debug_toolbar', 'bootstrapform', + 'kfet', ) MIDDLEWARE_CLASSES = ( diff --git a/cof/urls.py b/cof/urls.py index 5a4a49dc..64af9eda 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -78,6 +78,7 @@ urlpatterns = [ url(r'^utile_bda/bda_diff$', gestioncof_views.liste_bdadiff), url(r'^utile_cof/diff_cof$', gestioncof_views.liste_diffcof), 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) if settings.DEBUG diff --git a/kfet/__init__.py b/kfet/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/kfet/admin.py b/kfet/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/kfet/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/kfet/autocomplete.py b/kfet/autocomplete.py new file mode 100644 index 00000000..70293475 --- /dev/null +++ b/kfet/autocomplete.py @@ -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) diff --git a/kfet/forms.py b/kfet/forms.py new file mode 100644 index 00000000..2173e5a2 --- /dev/null +++ b/kfet/forms.py @@ -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': '' + } diff --git a/kfet/migrations/0001_initial.py b/kfet/migrations/0001_initial.py new file mode 100644 index 00000000..4bc9ccdb --- /dev/null +++ b/kfet/migrations/0001_initial.py @@ -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'), + ), + ] diff --git a/kfet/migrations/__init__.py b/kfet/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/kfet/models.py b/kfet/models.py new file mode 100644 index 00000000..2b2750ab --- /dev/null +++ b/kfet/models.py @@ -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) diff --git a/kfet/templates/kfet/account_new.html b/kfet/templates/kfet/account_new.html new file mode 100644 index 00000000..b7b28d88 --- /dev/null +++ b/kfet/templates/kfet/account_new.html @@ -0,0 +1,74 @@ +{% extends "kfet/base.html" %} +{% load static %} + +{% block title %}Création d'un nouveau compte{% endblock %} + +{% block extra_head %} + + +{% endblock %} + +{% block content %} +