gestioCOF/kfet/models.py

795 lines
28 KiB
Python
Raw Normal View History

2016-09-01 00:45:44 +02:00
# -*- coding: utf-8 -*-
2016-08-02 10:40:46 +02:00
from django.db import models
from django.core.urlresolvers import reverse
2016-08-02 10:40:46 +02:00
from django.core.validators import RegexValidator
from django.contrib.auth.models import User
2016-08-02 10:40:46 +02:00
from gestioncof.models import CofProfile
from django.utils.six.moves import reduce
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
from django.utils import timezone
2016-09-01 01:02:15 +02:00
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
2016-08-11 15:14:23 +02:00
from django.db import transaction
from django.db.models import F
from datetime import date
import re
2016-08-02 10:40:46 +02:00
from .auth import KFET_GENERIC_TRIGRAMME
from .auth.models import GenericTeamToken, Group, Permission # noqa
from .utils import to_ukf
2016-08-02 10:40:46 +02:00
def choices_length(choices):
return reduce(lambda m, choice: max(m, len(choice[0])), choices, 0)
def default_promo():
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
now = date.today()
2016-08-02 10:40:46 +02:00
return now.month <= 8 and now.year-1 or now.year
class AccountManager(models.Manager):
"""Manager for Account Model."""
def get_queryset(self):
"""Always append related data to this Account."""
return super().get_queryset().select_related('cofprofile__user',
'negative')
def get_generic(self):
"""
Get the kfet generic account instance.
"""
return self.get(trigramme=KFET_GENERIC_TRIGRAMME)
2017-09-22 23:31:46 +02:00
def get_by_password(self, password):
"""
Get a kfet generic account by clear password.
Raises Account.DoesNotExist if no Account has this password.
"""
from .auth.utils import hash_password
if password is None:
raise self.model.DoesNotExist
return self.get(password=hash_password(password))
2016-08-02 10:40:46 +02:00
class Account(models.Model):
objects = AccountManager()
2016-08-02 10:40:46 +02:00
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}$')],
db_index = True)
2016-08-02 10:40:46 +02:00
balance = models.DecimalField(
max_digits = 6, decimal_places = 2,
default = 0)
2017-03-31 02:31:16 +02:00
is_frozen = models.BooleanField("est gelé", default = False)
2017-04-06 00:31:04 +02:00
created_at = models.DateTimeField(default=timezone.now)
2016-08-02 10:40:46 +02:00
# Optional
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
PROMO_CHOICES = [(r,r) for r in range(1980, date.today().year+1)]
2016-08-02 10:40:46 +02:00
promo = models.IntegerField(
choices = PROMO_CHOICES,
blank = True, null = True, default = default_promo())
nickname = models.CharField(
2017-03-31 02:31:16 +02:00
"surnom(s)",
2016-08-02 10:40:46 +02:00
max_length = 255,
blank = True, default = "")
password = models.CharField(
max_length = 255,
unique = True,
blank = True, null = True, default = None)
2017-05-23 13:47:40 +02:00
class Meta:
verbose_name = _("Compte")
verbose_name_plural = _("Comptes")
default_permissions = ('add', 'change')
2017-05-23 13:47:40 +02:00
permissions = (
('is_team', "Membre de l'équipe"),
2017-05-23 13:47:40 +02:00
('manage_addcosts', 'Gérer les majorations'),
('edit_balance_account', "Modifier la balance d'un compte"),
('change_account_password',
"Modifier le mot de passe d'une personne de l'équipe"),
('special_add_account',
"Créer un compte avec une balance initiale"),
2017-06-21 23:31:27 +02:00
('can_force_close', "Fermer manuellement la K-Fêt"),
2017-05-23 13:47:40 +02:00
)
2016-08-02 10:40:46 +02:00
def __str__(self):
return '%s (%s)' % (self.trigramme, self.name)
# Propriétés pour accéder aux attributs de cofprofile et user
@property
def user(self):
return self.cofprofile.user
@property
def username(self):
return self.cofprofile.user.username
@property
def first_name(self):
return self.cofprofile.user.first_name
@property
def last_name(self):
return self.cofprofile.user.last_name
@property
def email(self):
return self.cofprofile.user.email
@property
def departement(self):
return self.cofprofile.departement
@property
def is_cof(self):
return self.cofprofile.is_cof
# Propriétés supplémentaires
@property
def balance_ukf(self):
return to_ukf(self.balance, is_cof=self.is_cof)
@property
def real_balance(self):
if hasattr(self, 'negative') and self.negative.balance_offset:
2016-09-05 19:19:09 +02:00
return self.balance - self.negative.balance_offset
return self.balance
@property
def name(self):
return self.user.get_full_name()
2016-08-02 10:40:46 +02:00
@property
def is_cash(self):
return self.trigramme == 'LIQ'
@property
def need_comment(self):
return self.trigramme == '#13'
@property
def readable(self):
return self.trigramme != 'GNR'
@property
def is_team(self):
return self.has_perm('kfet.is_team')
2016-08-02 10:40:46 +02:00
@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
2016-08-02 10:40:46 +02:00
try:
account = Account.objects.get(trigramme=trigramme)
2016-08-02 10:40:46 +02:00
except Account.DoesNotExist:
data['is_free'] = True
return data
2016-08-02 10:40:46 +02:00
2016-08-26 15:30:40 +02:00
def perms_to_perform_operation(self, amount):
from .config import kfet_config
overdraft_duration_max = kfet_config.overdraft_duration
overdraft_amount_max = kfet_config.overdraft_amount
2016-08-09 11:02:26 +02:00
perms = set()
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
stop_ope = False
# Checking is cash account
if self.is_cash:
# Yes, so no perms and no stop
return set(), False
if self.need_comment:
perms.add('kfet.perform_commented_operations')
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
# Checking is frozen account
if self.is_frozen:
2016-08-09 11:02:26 +02:00
perms.add('kfet.override_frozen_protection')
new_balance = self.balance + amount
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
if new_balance < 0 and amount < 0:
# Retrieving overdraft amount limit
if (hasattr(self, 'negative')
and self.negative.authz_overdraft_amount is not None):
overdraft_amount = - self.negative.authz_overdraft_amount
else:
2016-08-09 11:02:26 +02:00
overdraft_amount = - overdraft_amount_max
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
# Retrieving overdraft datetime limit
if (hasattr(self, 'negative')
and self.negative.authz_overdraft_until is not None):
overdraft_until = self.negative.authz_overdraft_until
elif hasattr(self, 'negative'):
overdraft_until = \
2016-08-09 11:02:26 +02:00
self.negative.start + overdraft_duration_max
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
else:
2016-08-09 11:02:26 +02:00
overdraft_until = timezone.now() + overdraft_duration_max
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
# Checking it doesn't break 1 rule
if new_balance < overdraft_amount or timezone.now() > overdraft_until:
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
stop_ope = True
2016-08-09 11:02:26 +02:00
perms.add('kfet.perform_negative_operations')
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
return perms, stop_ope
# Surcharge Méthode save() avec gestions de User et CofProfile
2016-08-02 10:40:46 +02:00
# Args:
# - data : datas pour User et CofProfile
# Action:
# - Enregistre User, CofProfile à partir de "data"
# - Enregistre Account
def save(self, data = {}, *args, **kwargs):
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
if self.pk and data:
2016-08-02 10:40:46 +02:00
# Account update
# Updating User with data
user = self.user
2016-08-02 10:40:46 +02:00
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()
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
elif data:
2016-08-02 10:40:46 +02:00
# 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
2016-08-02 10:40:46 +02:00
# 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()
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
if data:
self.cofprofile = cof
super(Account, self).save(*args, **kwargs)
2016-08-02 10:40:46 +02:00
2017-09-22 23:31:46 +02:00
def change_pwd(self, clear_password):
from .auth.utils import hash_password
self.password = hash_password(clear_password)
2016-08-02 10:40:46 +02:00
# Surcharge de delete
# Pas de suppression possible
# Cas à régler plus tard
def delete(self, *args, **kwargs):
pass
def update_negative(self):
if self.real_balance < 0:
if hasattr(self, 'negative') and not self.negative.start:
self.negative.start = timezone.now()
self.negative.save()
elif not hasattr(self, 'negative'):
self.negative = (
AccountNegative.objects.create(
account=self, start=timezone.now(),
)
)
elif hasattr(self, 'negative'):
# self.real_balance >= 0
balance_offset = self.negative.balance_offset
if balance_offset:
(
Account.objects
.filter(pk=self.pk)
.update(balance=F('balance')-balance_offset)
)
self.refresh_from_db()
self.negative.delete()
2016-08-02 10:40:46 +02:00
class UserHasAccount(Exception):
def __init__(self, trigramme):
self.trigramme = trigramme
class AccountNegativeManager(models.Manager):
"""Manager for AccountNegative model."""
def get_queryset(self):
return (
super().get_queryset()
.select_related('account__cofprofile__user')
)
2016-08-02 10:40:46 +02:00
class AccountNegative(models.Model):
objects = AccountNegativeManager()
2016-08-02 10:40:46 +02:00
account = models.OneToOneField(
Account, on_delete=models.PROTECT,
related_name="negative",
)
start = models.DateTimeField(blank=True, null=True, default=None)
balance_offset = models.DecimalField(
2017-03-31 02:31:16 +02:00
"décalage de balance",
help_text="Montant non compris dans l'autorisation de négatif",
max_digits=6, decimal_places=2,
blank=True, null=True, default=None,
)
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
authz_overdraft_amount = models.DecimalField(
2017-03-31 02:31:16 +02:00
"négatif autorisé",
max_digits=6, decimal_places=2,
blank=True, null=True, default=None,
)
Gestion des commandes K-Psul donnant un négatif * Settings - New: OVERDRAFT_AMOUNT Découvert autorisé par défaut - New: OVERDRAFT_DURATION Durée maximum d'un découvert par défaut * K-Psul : Gestion des commandes aboutissant à un négatif - Si une commande aboutit à un nouveau solde négatif, demande la permission 'kfet.perform_negative_operations' - Si le total de la commande est négatif, vérifie que ni la contrainte de temps de découvert, ni celle de montant maximum n'est outrepassée. Si ce n'est pas le cas, la commande ne peut être enregistrée jusqu'à définir des "règles de négatif" pour le compte concerné. La durée maximum d'un découvert est celle dans AccountNegative si elle y est définie pour le compte concerné, sinon celle par défaut (Settings.OVERDRAFT_DURATION). Il en est de même pour le découvert maximum autorisé. Attention: le découvert doit être exprimé sous forme de valeur positive aussi bien dans AccountNegative que pour Settings.OVERDRAFT_AMOUNT. - Si les permissions nécessaires sont présentes, qu'il n'y a pas de blocage et que le compte n'a pas encore d'entrée dans AccountNegative, création d'une entrée avec start=now() - Si la balance d'un compte est positive après une commande, supprime l'entrée dans AccountNegative associée au compte si le "décalage de zéro" (donné par balance_offset) est nul. Sinon cela veut dire que le compte n'est pas réellement en positif. * Modèles - Fix: Account.save() fonctionne dans le cas où data est vide - Modif: AccountNegative - Valeurs par défaut, NULL...
2016-08-08 07:44:05 +02:00
authz_overdraft_until = models.DateTimeField(
2017-03-31 02:31:16 +02:00
"expiration du négatif",
blank=True, null=True, default=None,
)
comment = models.CharField("commentaire", max_length=255, blank=True)
2017-05-23 13:47:40 +02:00
class Meta:
verbose_name = _("Compte en négatif")
verbose_name_plural = _("Comptes en négatif")
default_permissions = ('view', 'change')
2017-05-23 13:47:40 +02:00
@property
def until_default(self):
from .config import kfet_config
return self.start + kfet_config.overdraft_duration
2016-08-02 10:40:46 +02:00
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,
default = 0)
2016-08-02 10:40:46 +02:00
is_protected = models.BooleanField(default = False)
def get_absolute_url(self):
return reverse('kfet.checkout.read', kwargs={'pk': self.pk})
class Meta:
verbose_name = _("Caisse")
verbose_name_plural = _("Caisses")
ordering = ['-valid_to']
default_permissions = ('add', 'change')
def __str__(self):
return self.name
2016-08-02 10:40:46 +02:00
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 Meta:
default_permissions = ()
2016-09-01 01:02:15 +02:00
@python_2_unicode_compatible
class CheckoutStatement(models.Model):
2016-08-02 10:40:46 +02:00
by = models.ForeignKey(
Account, on_delete = models.PROTECT,
related_name = "+")
checkout = models.ForeignKey(
Checkout, on_delete = models.PROTECT,
related_name = "statements")
2017-03-31 02:38:16 +02:00
balance_old = models.DecimalField("ancienne balance",
2017-03-31 02:10:50 +02:00
max_digits = 6, decimal_places = 2)
2017-03-31 02:38:16 +02:00
balance_new = models.DecimalField("nouvelle balance",
2017-03-31 02:10:50 +02:00
max_digits = 6, decimal_places = 2)
2017-03-31 02:38:16 +02:00
amount_taken = models.DecimalField("montant pris",
2017-03-31 02:10:50 +02:00
max_digits = 6, decimal_places = 2)
2017-03-31 02:38:16 +02:00
amount_error = models.DecimalField("montant de l'erreur",
2017-03-31 02:10:50 +02:00
max_digits = 6, decimal_places = 2)
2016-08-02 10:40:46 +02:00
at = models.DateTimeField(auto_now_add = True)
2017-03-31 02:38:16 +02:00
not_count = models.BooleanField("caisse non comptée", default=False)
2016-08-02 10:40:46 +02:00
2017-03-31 02:38:16 +02:00
taken_001 = models.PositiveSmallIntegerField("pièces de 1¢", default=0)
taken_002 = models.PositiveSmallIntegerField("pièces de 2¢", default=0)
taken_005 = models.PositiveSmallIntegerField("pièces de 5¢", default=0)
taken_01 = models.PositiveSmallIntegerField("pièces de 10¢", default=0)
taken_02 = models.PositiveSmallIntegerField("pièces de 20¢", default=0)
taken_05 = models.PositiveSmallIntegerField("pièces de 50¢", default=0)
taken_1 = models.PositiveSmallIntegerField("pièces de 1€", default=0)
taken_2 = models.PositiveSmallIntegerField("pièces de 2€", default=0)
taken_5 = models.PositiveSmallIntegerField("billets de 5€", default=0)
taken_10 = models.PositiveSmallIntegerField("billets de 10€", default=0)
taken_20 = models.PositiveSmallIntegerField("billets de 20€", default=0)
taken_50 = models.PositiveSmallIntegerField("billets de 50€", default=0)
taken_100 = models.PositiveSmallIntegerField("billets de 100€", default=0)
taken_200 = models.PositiveSmallIntegerField("billets de 200€", default=0)
taken_500 = models.PositiveSmallIntegerField("billets de 500€", default=0)
2017-03-31 02:10:50 +02:00
taken_cheque = models.DecimalField(
2017-03-31 02:38:16 +02:00
"montant des chèques",
2017-03-31 02:10:50 +02:00
default=0, max_digits=6, decimal_places=2)
class Meta:
verbose_name = _("Relevé de caisse")
verbose_name_plural = _("Relevés de caisses")
default_permissions = ('add', 'change')
2016-08-11 15:14:23 +02:00
def __str__(self):
return '%s %s' % (self.checkout, self.at)
def save(self, *args, **kwargs):
if not self.pk:
checkout_id = self.checkout_id
self.balance_old = (Checkout.objects
.values_list('balance', flat=True).get(pk=checkout_id))
if self.not_count:
self.balance_new = self.balance_old - self.amount_taken
2016-08-11 15:14:23 +02:00
self.amount_error = (
self.balance_new + self.amount_taken - self.balance_old)
2016-08-11 15:14:23 +02:00
with transaction.atomic():
Checkout.objects.filter(pk=checkout_id).update(balance=self.balance_new)
super(CheckoutStatement, self).save(*args, **kwargs)
else:
self.amount_error = (
self.balance_new + self.amount_taken - self.balance_old)
# Si on modifie le dernier relevé d'une caisse et que la nouvelle
# balance est modifiée alors on modifie la balance actuelle de la caisse
last_statement = (CheckoutStatement.objects
.filter(checkout=self.checkout)
.order_by('at')
.last())
if (last_statement.pk == self.pk
and last_statement.balance_new != self.balance_new):
Checkout.objects.filter(pk=self.checkout_id).update(
balance=F('balance') - last_statement.balance_new + self.balance_new)
2016-08-11 15:14:23 +02:00
super(CheckoutStatement, self).save(*args, **kwargs)
2017-03-10 18:28:48 +01:00
2016-09-01 01:02:15 +02:00
@python_2_unicode_compatible
2016-08-02 10:40:46 +02:00
class ArticleCategory(models.Model):
name = models.CharField("nom", max_length=45)
has_addcost = models.BooleanField("majorée", default=True,
help_text="Si oui et qu'une majoration "
"est active, celle-ci sera "
"appliquée aux articles de "
"cette catégorie.")
2016-08-02 10:40:46 +02:00
class Meta:
verbose_name = _("Catégorie d'articles")
verbose_name_plural = _("Catégories d'articles")
default_permissions = ('change',)
def __str__(self):
return self.name
2017-03-10 18:28:48 +01:00
2016-09-01 01:02:15 +02:00
@python_2_unicode_compatible
2016-08-02 10:40:46 +02:00
class Article(models.Model):
name = models.CharField("nom", max_length = 45)
is_sold = models.BooleanField("en vente", default = True)
hidden = models.BooleanField("caché",
default=False,
help_text="Si oui, ne sera pas affiché "
"au public ; par exemple "
"sur la carte.")
price = models.DecimalField(
"prix",
max_digits = 6, decimal_places = 2,
default = 0)
stock = models.IntegerField(default = 0)
2016-08-02 10:40:46 +02:00
category = models.ForeignKey(
ArticleCategory, on_delete = models.PROTECT,
related_name = "articles", verbose_name='catégorie')
BOX_TYPE_CHOICES = (
("caisse", "caisse"),
("carton", "carton"),
("palette", "palette"),
("fût", "fût"),
)
box_type = models.CharField(
"type de contenant",
choices = BOX_TYPE_CHOICES,
max_length = choices_length(BOX_TYPE_CHOICES),
blank = True, null = True, default = None)
box_capacity = models.PositiveSmallIntegerField(
"capacité du contenant",
blank = True, null = True, default = None)
2016-08-02 10:40:46 +02:00
class Meta:
verbose_name = _("Article")
verbose_name_plural = _("Articles")
default_permissions = ('add', 'change')
def __str__(self):
return '%s - %s' % (self.category.name, self.name)
def get_absolute_url(self):
return reverse('kfet.article.read', kwargs={'pk': self.pk})
def price_ukf(self):
return to_ukf(self.price)
2016-08-02 10:40:46 +02:00
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 Meta:
default_permissions = ()
2016-08-02 10:40:46 +02:00
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 Meta:
verbose_name = _("Inventaire")
verbose_name_plural = _("Inventaires")
ordering = ['-at']
default_permissions = ('add',)
2017-05-23 13:47:40 +02:00
permissions = (
('order_to_inventory', "Générer un inventaire à partir d'une commande"),
)
2016-08-02 10:40:46 +02:00
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 Meta:
default_permissions = ()
def save(self, *args, **kwargs):
# S'il s'agit d'un inventaire provenant d'une livraison, il n'y a pas
# d'erreur
2016-09-03 18:04:00 +02:00
if not self.inventory.order:
self.stock_error = self.stock_new - self.stock_old
super(InventoryArticle, self).save(*args, **kwargs)
2016-09-01 01:02:15 +02:00
@python_2_unicode_compatible
2016-08-02 10:40:46 +02:00
class Supplier(models.Model):
articles = models.ManyToManyField(
Article,
through = 'SupplierArticle',
related_name = "suppliers")
2017-03-31 02:16:47 +02:00
name = models.CharField("nom", max_length = 45)
address = models.TextField("adresse")
email = models.EmailField("adresse mail")
phone = models.CharField("téléphone", max_length = 10)
comment = models.TextField("commentaire")
2016-08-02 10:40:46 +02:00
class Meta:
verbose_name = _("Fournisseur")
verbose_name_plural = _("Fournisseurs")
default_permissions = ('change',)
def __str__(self):
return self.name
2016-08-02 10:40:46 +02:00
class SupplierArticle(models.Model):
supplier = models.ForeignKey(
Supplier, on_delete = models.PROTECT)
article = models.ForeignKey(
Article, on_delete = models.PROTECT)
at = models.DateTimeField(auto_now_add = True)
price_HT = models.DecimalField(
max_digits = 7, decimal_places = 4,
blank = True, null = True, default = None)
TVA = models.DecimalField(
max_digits = 4, decimal_places = 2,
blank = True, null = True, default = None)
rights = models.DecimalField(
max_digits = 7, decimal_places = 4,
blank = True, null = True, default = None)
2016-08-02 10:40:46 +02:00
class Meta:
default_permissions = ()
2016-08-02 10:40:46 +02:00
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, default = 0)
class Meta:
verbose_name = _("Commande")
verbose_name_plural = _("Commandes")
ordering = ['-at']
default_permissions = ('add',)
2016-08-02 10:40:46 +02:00
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(default = 0)
2016-08-02 10:40:46 +02:00
class Meta:
default_permissions = ()
2016-08-02 10:40:46 +02:00
class TransferGroup(models.Model):
2017-03-21 00:19:04 +01:00
at = models.DateTimeField(default=timezone.now)
2016-08-02 10:40:46 +02:00
# 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 Meta:
default_permissions = ()
2016-08-02 10:40:46 +02:00
class Transfer(models.Model):
group = models.ForeignKey(
TransferGroup, on_delete=models.PROTECT,
related_name="transfers")
2016-08-02 10:40:46 +02:00
from_acc = models.ForeignKey(
Account, on_delete=models.PROTECT,
related_name="transfers_from")
2016-08-02 10:40:46 +02:00
to_acc = models.ForeignKey(
Account, on_delete=models.PROTECT,
related_name="transfers_to")
amount = models.DecimalField(max_digits=6, decimal_places=2)
2016-08-02 10:40:46 +02:00
# Optional
canceled_by = models.ForeignKey(
Account, on_delete=models.PROTECT,
null=True, blank=True, default=None,
related_name="+")
2016-08-02 10:40:46 +02:00
canceled_at = models.DateTimeField(
null=True, blank=True, default=None)
class Meta:
verbose_name = _("Transfert")
verbose_name_plural = _("Transferts")
default_permissions = ('add',)
def __str__(self):
return '{} -> {}: {}'.format(self.from_acc, self.to_acc, self.amount)
2016-08-02 10:40:46 +02:00
class OperationGroup(models.Model):
on_acc = models.ForeignKey(
Account, on_delete = models.PROTECT,
related_name = "opesgroup")
2016-08-02 10:40:46 +02:00
checkout = models.ForeignKey(
Checkout, on_delete = models.PROTECT,
related_name = "opesgroup")
2017-03-21 00:19:04 +01:00
at = models.DateTimeField(default=timezone.now)
amount = models.DecimalField(
max_digits = 6, decimal_places = 2,
default = 0)
2016-08-02 10:40:46 +02:00
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 = None)
2016-08-02 10:40:46 +02:00
class Meta:
default_permissions = ()
2016-12-24 12:33:04 +01:00
def __str__(self):
return ', '.join(map(str, self.opes.all()))
2016-08-02 10:40:46 +02:00
class Operation(models.Model):
PURCHASE = 'purchase'
2017-03-25 14:43:02 +01:00
DEPOSIT = 'deposit'
2016-08-02 10:40:46 +02:00
WITHDRAW = 'withdraw'
INITIAL = 'initial'
EDIT = 'edit'
2016-08-02 10:40:46 +02:00
TYPE_ORDER_CHOICES = (
(PURCHASE, 'Achat'),
(DEPOSIT, 'Charge'),
(WITHDRAW, 'Retrait'),
(INITIAL, 'Initial'),
(EDIT, 'Édition'),
2016-08-02 10:40:46 +02:00
)
group = models.ForeignKey(
2017-03-25 14:43:02 +01:00
OperationGroup, on_delete=models.PROTECT,
related_name="opes")
2016-08-02 10:40:46 +02:00
type = models.CharField(
2017-03-25 14:43:02 +01:00
choices=TYPE_ORDER_CHOICES,
max_length=choices_length(TYPE_ORDER_CHOICES))
amount = models.DecimalField(
2017-03-25 14:43:02 +01:00
max_digits=6, decimal_places=2,
blank=True, default=0)
2016-08-02 10:40:46 +02:00
# Optional
article = models.ForeignKey(
2017-03-25 14:43:02 +01:00
Article, on_delete=models.PROTECT,
related_name="operations",
blank=True, null=True, default=None)
article_nb = models.PositiveSmallIntegerField(
2017-03-25 14:43:02 +01:00
blank=True, null=True, default=None)
2016-08-02 10:40:46 +02:00
canceled_by = models.ForeignKey(
2017-03-25 14:43:02 +01:00
Account, on_delete=models.PROTECT,
related_name="+",
blank=True, null=True, default=None)
2016-08-02 10:40:46 +02:00
canceled_at = models.DateTimeField(
2017-03-25 14:43:02 +01:00
blank=True, null=True, default=None)
2016-08-02 10:40:46 +02:00
addcost_for = models.ForeignKey(
2017-03-25 14:43:02 +01:00
Account, on_delete=models.PROTECT,
related_name="addcosts",
blank=True, null=True, default=None)
addcost_amount = models.DecimalField(
2017-03-25 14:43:02 +01:00
max_digits=6, decimal_places=2,
blank=True, null=True, default=None)
2017-05-23 13:47:40 +02:00
class Meta:
verbose_name = _("Opération")
verbose_name_plural = _("Opérations")
default_permissions = ()
2017-05-23 13:47:40 +02:00
permissions = (
('perform_deposit', 'Effectuer une charge'),
('perform_negative_operations',
'Enregistrer des commandes en négatif'),
('override_frozen_protection', "Forcer le gel d'un compte"),
('cancel_old_operations', 'Annuler des commandes non récentes'),
('perform_commented_operations',
'Enregistrer des commandes avec commentaires'),
)
@property
def is_checkout(self):
2017-03-25 00:52:49 +01:00
return (self.type == Operation.DEPOSIT or
self.type == Operation.WITHDRAW or
2017-03-25 13:57:44 +01:00
(self.type == Operation.PURCHASE and self.group.on_acc.is_cash)
)
2016-12-24 12:33:04 +01:00
def __str__(self):
templates = {
self.PURCHASE: "{nb} {article.name} ({amount}€)",
2017-03-25 14:01:35 +01:00
self.DEPOSIT: "charge ({amount}€)",
self.WITHDRAW: "retrait ({amount}€)",
self.INITIAL: "initial ({amount}€)",
self.EDIT: "édition ({amount}€)",
2016-12-24 12:33:04 +01:00
}
return templates[self.type].format(nb=self.article_nb,
article=self.article,
amount=self.amount)