from django.db import models from django.core.exceptions import PermissionDenied from django.contrib.auth.models import User, AnonymousUser from django.core.validators import RegexValidator from gestioncof.models import CofProfile from django.utils.six.moves import reduce import datetime import re 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_validandfree(trigramme): data = { 'is_valid' : False, 'is_free' : False } pattern = re.compile("^[^a-z]{3}$") data['is_valid'] = pattern.match(trigramme) and True or False try: account = Account.objects.get(trigramme=trigramme) except Account.DoesNotExist: data['is_free'] = True return data def real_balance(self): if (hasattr(self, 'negative')): return self.balance + self.negative.balance_offset return self.balance def read(self, auth_user = AnonymousUser()): user = self.cofprofile.user # Surcharge Méthode save() avec gestions de User et CofProfile # Args: # - data : datas pour User et CofProfile # Action: # - Enregistre User, CofProfile à partir de "data" # - Enregistre Account def save(self, data = {}, *args, **kwargs): if self.pk: # Account update # Updating User with data user = self.cofprofile.user 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 if user has already an account username = data.get("username") try: user = User.objects.get(username=username) if hasattr(user.profile, "account_kfet"): trigramme = user.profile.account_kfet.trigramme raise Account.UserHasAccount(trigramme) except User.DoesNotExist: pass # Creating or updating User instance (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() self.cofprofile = cof super(Account, self).save(*args, **kwargs) # 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, default = 0) 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) class GlobalPermissions(models.Model): class Meta: managed = False permissions = ( ('is_team', 'Is part of the team'), )