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)