forked from DGNum/gestioCOF
Merge branch 'Aufinal/can-delete-stuff' into 'master'
Délétions d'objets K-Fêt See merge request klub-dev-ens/gestioCOF!359
This commit is contained in:
commit
7f1adf7c4e
14 changed files with 590 additions and 114 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
- On peut supprimer des comptes et des articles K-Fêt
|
||||||
- Passage à Django2
|
- Passage à Django2
|
||||||
- Dev : on peut désactiver la barre de debug avec une variable shell
|
- Dev : on peut désactiver la barre de debug avec une variable shell
|
||||||
- Remplace les CSS de Google par des polices de proximité
|
- Remplace les CSS de Google par des polices de proximité
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
default_app_config = "kfet.apps.KFetConfig"
|
default_app_config = "kfet.apps.KFetConfig"
|
||||||
|
KFET_DELETED_TRIGRAMME = "☠☠☠"
|
||||||
|
KFET_DELETED_USERNAME = "kfet_deleted_user"
|
||||||
|
|
97
kfet/migrations/0066_on_delete_actions.py
Normal file
97
kfet/migrations/0066_on_delete_actions.py
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
# Generated by Django 2.2 on 2019-05-23 13:20
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [("kfet", "0065_choices_promo")]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(model_name="checkouttransfer", name="from_checkout"),
|
||||||
|
migrations.RemoveField(model_name="checkouttransfer", name="to_checkout"),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="accountnegative",
|
||||||
|
name="account",
|
||||||
|
field=models.OneToOneField(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="negative",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="checkoutstatement",
|
||||||
|
name="checkout",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="statements",
|
||||||
|
to="kfet.Checkout",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="inventoryarticle",
|
||||||
|
name="article",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to="kfet.Article"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="inventoryarticle",
|
||||||
|
name="inventory",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to="kfet.Inventory"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="operation",
|
||||||
|
name="article",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="operations",
|
||||||
|
to="kfet.Article",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="order",
|
||||||
|
name="supplier",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="orders",
|
||||||
|
to="kfet.Supplier",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="orderarticle",
|
||||||
|
name="article",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to="kfet.Article"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="orderarticle",
|
||||||
|
name="order",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to="kfet.Order"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="supplierarticle",
|
||||||
|
name="article",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to="kfet.Article"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="supplierarticle",
|
||||||
|
name="supplier",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to="kfet.Supplier"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(name="ArticleRule"),
|
||||||
|
migrations.DeleteModel(name="CheckoutTransfer"),
|
||||||
|
]
|
32
kfet/migrations/0067_deleted_account.py
Normal file
32
kfet/migrations/0067_deleted_account.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# Generated by Django 2.2 on 2019-05-23 13:54
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
from kfet import KFET_DELETED_TRIGRAMME, KFET_DELETED_USERNAME
|
||||||
|
|
||||||
|
|
||||||
|
def setup_kfet_deleted_user(apps, schema_editor):
|
||||||
|
"""
|
||||||
|
Setup models instances for the kfet deleted account.
|
||||||
|
|
||||||
|
Username and trigramme are retrieved from kfet.__init__ module.
|
||||||
|
Other data are registered here.
|
||||||
|
"""
|
||||||
|
User = apps.get_model("auth", "User")
|
||||||
|
CofProfile = apps.get_model("gestioncof", "CofProfile")
|
||||||
|
Account = apps.get_model("kfet", "Account")
|
||||||
|
|
||||||
|
user, _ = User.objects.update_or_create(
|
||||||
|
username=KFET_DELETED_USERNAME, defaults={"first_name": "Compte K-Fêt supprimé"}
|
||||||
|
)
|
||||||
|
profile, _ = CofProfile.objects.update_or_create(user=user)
|
||||||
|
account, _ = Account.objects.update_or_create(
|
||||||
|
cofprofile=profile, defaults={"trigramme": KFET_DELETED_TRIGRAMME}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [("kfet", "0066_on_delete_actions")]
|
||||||
|
|
||||||
|
operations = [migrations.RunPython(setup_kfet_deleted_user)]
|
127
kfet/migrations/0068_on_delete_account.py
Normal file
127
kfet/migrations/0068_on_delete_account.py
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
# Generated by Django 2.2 on 2019-05-23 16:17
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import kfet.models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [("kfet", "0067_deleted_account")]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="checkout",
|
||||||
|
name="created_by",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=models.SET(kfet.models.get_deleted_account),
|
||||||
|
related_name="+",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="checkoutstatement",
|
||||||
|
name="by",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=models.SET(kfet.models.get_deleted_account),
|
||||||
|
related_name="+",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="inventory",
|
||||||
|
name="by",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=models.SET(kfet.models.get_deleted_account),
|
||||||
|
related_name="+",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="operation",
|
||||||
|
name="addcost_for",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
on_delete=models.SET(kfet.models.get_deleted_account),
|
||||||
|
related_name="addcosts",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="operation",
|
||||||
|
name="canceled_by",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
on_delete=models.SET(kfet.models.get_deleted_account),
|
||||||
|
related_name="+",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="operationgroup",
|
||||||
|
name="on_acc",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=models.SET(kfet.models.get_deleted_account),
|
||||||
|
related_name="opesgroup",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="operationgroup",
|
||||||
|
name="valid_by",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
on_delete=models.SET(kfet.models.get_deleted_account),
|
||||||
|
related_name="+",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="transfer",
|
||||||
|
name="canceled_by",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
on_delete=models.SET(kfet.models.get_deleted_account),
|
||||||
|
related_name="+",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="transfer",
|
||||||
|
name="from_acc",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=models.SET(kfet.models.get_deleted_account),
|
||||||
|
related_name="transfers_from",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="transfer",
|
||||||
|
name="to_acc",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=models.SET(kfet.models.get_deleted_account),
|
||||||
|
related_name="transfers_to",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="transfergroup",
|
||||||
|
name="valid_by",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
on_delete=models.SET(kfet.models.get_deleted_account),
|
||||||
|
related_name="+",
|
||||||
|
to="kfet.Account",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -12,6 +12,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from gestioncof.models import CofProfile
|
from gestioncof.models import CofProfile
|
||||||
|
|
||||||
|
from . import KFET_DELETED_TRIGRAMME
|
||||||
from .auth import KFET_GENERIC_TRIGRAMME
|
from .auth import KFET_GENERIC_TRIGRAMME
|
||||||
from .auth.models import GenericTeamToken # noqa
|
from .auth.models import GenericTeamToken # noqa
|
||||||
from .config import kfet_config
|
from .config import kfet_config
|
||||||
|
@ -151,7 +152,7 @@ class Account(models.Model):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def readable(self):
|
def readable(self):
|
||||||
return self.trigramme != "GNR"
|
return self.trigramme not in [KFET_DELETED_TRIGRAMME, KFET_GENERIC_TRIGRAMME]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_team(self):
|
def is_team(self):
|
||||||
|
@ -267,12 +268,6 @@ class Account(models.Model):
|
||||||
|
|
||||||
self.password = hash_password(clear_password)
|
self.password = hash_password(clear_password)
|
||||||
|
|
||||||
# Surcharge de delete
|
|
||||||
# Pas de suppression possible
|
|
||||||
# Cas à régler plus tard
|
|
||||||
def delete(self, *args, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def update_negative(self):
|
def update_negative(self):
|
||||||
if self.real_balance < 0:
|
if self.real_balance < 0:
|
||||||
if hasattr(self, "negative") and not self.negative.start:
|
if hasattr(self, "negative") and not self.negative.start:
|
||||||
|
@ -299,6 +294,10 @@ class Account(models.Model):
|
||||||
self.trigramme = trigramme
|
self.trigramme = trigramme
|
||||||
|
|
||||||
|
|
||||||
|
def get_deleted_account():
|
||||||
|
return Account.objects.get(trigramme=KFET_DELETED_TRIGRAMME)
|
||||||
|
|
||||||
|
|
||||||
class AccountNegativeManager(models.Manager):
|
class AccountNegativeManager(models.Manager):
|
||||||
"""Manager for AccountNegative model."""
|
"""Manager for AccountNegative model."""
|
||||||
|
|
||||||
|
@ -310,7 +309,7 @@ class AccountNegative(models.Model):
|
||||||
objects = AccountNegativeManager()
|
objects = AccountNegativeManager()
|
||||||
|
|
||||||
account = models.OneToOneField(
|
account = models.OneToOneField(
|
||||||
Account, on_delete=models.PROTECT, related_name="negative"
|
Account, on_delete=models.CASCADE, related_name="negative"
|
||||||
)
|
)
|
||||||
start = models.DateTimeField(blank=True, null=True, default=None)
|
start = models.DateTimeField(blank=True, null=True, default=None)
|
||||||
balance_offset = models.DecimalField(
|
balance_offset = models.DecimalField(
|
||||||
|
@ -350,7 +349,9 @@ class CheckoutQuerySet(models.QuerySet):
|
||||||
|
|
||||||
|
|
||||||
class Checkout(models.Model):
|
class Checkout(models.Model):
|
||||||
created_by = models.ForeignKey(Account, on_delete=models.PROTECT, related_name="+")
|
created_by = models.ForeignKey(
|
||||||
|
Account, on_delete=models.SET(get_deleted_account), related_name="+"
|
||||||
|
)
|
||||||
name = models.CharField(max_length=45)
|
name = models.CharField(max_length=45)
|
||||||
valid_from = models.DateTimeField()
|
valid_from = models.DateTimeField()
|
||||||
valid_to = models.DateTimeField()
|
valid_to = models.DateTimeField()
|
||||||
|
@ -384,20 +385,12 @@ class Checkout(models.Model):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
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 CheckoutStatement(models.Model):
|
class CheckoutStatement(models.Model):
|
||||||
by = models.ForeignKey(Account, on_delete=models.PROTECT, related_name="+")
|
by = models.ForeignKey(
|
||||||
|
Account, on_delete=models.SET(get_deleted_account), related_name="+"
|
||||||
|
)
|
||||||
checkout = models.ForeignKey(
|
checkout = models.ForeignKey(
|
||||||
Checkout, on_delete=models.PROTECT, related_name="statements"
|
Checkout, on_delete=models.CASCADE, related_name="statements"
|
||||||
)
|
)
|
||||||
balance_old = models.DecimalField(
|
balance_old = models.DecimalField(
|
||||||
"ancienne balance", max_digits=6, decimal_places=2
|
"ancienne balance", max_digits=6, decimal_places=2
|
||||||
|
@ -526,21 +519,13 @@ class Article(models.Model):
|
||||||
return to_ukf(self.price)
|
return to_ukf(self.price)
|
||||||
|
|
||||||
|
|
||||||
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):
|
class Inventory(models.Model):
|
||||||
articles = models.ManyToManyField(
|
articles = models.ManyToManyField(
|
||||||
Article, through="InventoryArticle", related_name="inventories"
|
Article, through="InventoryArticle", related_name="inventories"
|
||||||
)
|
)
|
||||||
by = models.ForeignKey(Account, on_delete=models.PROTECT, related_name="+")
|
by = models.ForeignKey(
|
||||||
|
Account, on_delete=models.SET(get_deleted_account), related_name="+"
|
||||||
|
)
|
||||||
at = models.DateTimeField(auto_now_add=True)
|
at = models.DateTimeField(auto_now_add=True)
|
||||||
# Optional
|
# Optional
|
||||||
order = models.OneToOneField(
|
order = models.OneToOneField(
|
||||||
|
@ -560,8 +545,8 @@ class Inventory(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class InventoryArticle(models.Model):
|
class InventoryArticle(models.Model):
|
||||||
inventory = models.ForeignKey(Inventory, on_delete=models.PROTECT)
|
inventory = models.ForeignKey(Inventory, on_delete=models.CASCADE)
|
||||||
article = models.ForeignKey(Article, on_delete=models.PROTECT)
|
article = models.ForeignKey(Article, on_delete=models.CASCADE)
|
||||||
stock_old = models.IntegerField()
|
stock_old = models.IntegerField()
|
||||||
stock_new = models.IntegerField()
|
stock_new = models.IntegerField()
|
||||||
stock_error = models.IntegerField(default=0)
|
stock_error = models.IntegerField(default=0)
|
||||||
|
@ -592,8 +577,8 @@ class Supplier(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class SupplierArticle(models.Model):
|
class SupplierArticle(models.Model):
|
||||||
supplier = models.ForeignKey(Supplier, on_delete=models.PROTECT)
|
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
|
||||||
article = models.ForeignKey(Article, on_delete=models.PROTECT)
|
article = models.ForeignKey(Article, on_delete=models.CASCADE)
|
||||||
at = models.DateTimeField(auto_now_add=True)
|
at = models.DateTimeField(auto_now_add=True)
|
||||||
price_HT = models.DecimalField(
|
price_HT = models.DecimalField(
|
||||||
max_digits=7, decimal_places=4, blank=True, null=True, default=None
|
max_digits=7, decimal_places=4, blank=True, null=True, default=None
|
||||||
|
@ -608,7 +593,7 @@ class SupplierArticle(models.Model):
|
||||||
|
|
||||||
class Order(models.Model):
|
class Order(models.Model):
|
||||||
supplier = models.ForeignKey(
|
supplier = models.ForeignKey(
|
||||||
Supplier, on_delete=models.PROTECT, related_name="orders"
|
Supplier, on_delete=models.CASCADE, related_name="orders"
|
||||||
)
|
)
|
||||||
articles = models.ManyToManyField(
|
articles = models.ManyToManyField(
|
||||||
Article, through="OrderArticle", related_name="orders"
|
Article, through="OrderArticle", related_name="orders"
|
||||||
|
@ -621,8 +606,8 @@ class Order(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class OrderArticle(models.Model):
|
class OrderArticle(models.Model):
|
||||||
order = models.ForeignKey(Order, on_delete=models.PROTECT)
|
order = models.ForeignKey(Order, on_delete=models.CASCADE)
|
||||||
article = models.ForeignKey(Article, on_delete=models.PROTECT)
|
article = models.ForeignKey(Article, on_delete=models.CASCADE)
|
||||||
quantity_ordered = models.IntegerField()
|
quantity_ordered = models.IntegerField()
|
||||||
quantity_received = models.IntegerField(default=0)
|
quantity_received = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
@ -633,7 +618,7 @@ class TransferGroup(models.Model):
|
||||||
comment = models.CharField(max_length=255, blank=True, default="")
|
comment = models.CharField(max_length=255, blank=True, default="")
|
||||||
valid_by = models.ForeignKey(
|
valid_by = models.ForeignKey(
|
||||||
Account,
|
Account,
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.SET(get_deleted_account),
|
||||||
related_name="+",
|
related_name="+",
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
|
@ -646,16 +631,18 @@ class Transfer(models.Model):
|
||||||
TransferGroup, on_delete=models.PROTECT, related_name="transfers"
|
TransferGroup, on_delete=models.PROTECT, related_name="transfers"
|
||||||
)
|
)
|
||||||
from_acc = models.ForeignKey(
|
from_acc = models.ForeignKey(
|
||||||
Account, on_delete=models.PROTECT, related_name="transfers_from"
|
Account,
|
||||||
|
on_delete=models.SET(get_deleted_account),
|
||||||
|
related_name="transfers_from",
|
||||||
)
|
)
|
||||||
to_acc = models.ForeignKey(
|
to_acc = models.ForeignKey(
|
||||||
Account, on_delete=models.PROTECT, related_name="transfers_to"
|
Account, on_delete=models.SET(get_deleted_account), related_name="transfers_to"
|
||||||
)
|
)
|
||||||
amount = models.DecimalField(max_digits=6, decimal_places=2)
|
amount = models.DecimalField(max_digits=6, decimal_places=2)
|
||||||
# Optional
|
# Optional
|
||||||
canceled_by = models.ForeignKey(
|
canceled_by = models.ForeignKey(
|
||||||
Account,
|
Account,
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.SET(get_deleted_account),
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
default=None,
|
default=None,
|
||||||
|
@ -669,7 +656,7 @@ class Transfer(models.Model):
|
||||||
|
|
||||||
class OperationGroup(models.Model):
|
class OperationGroup(models.Model):
|
||||||
on_acc = models.ForeignKey(
|
on_acc = models.ForeignKey(
|
||||||
Account, on_delete=models.PROTECT, related_name="opesgroup"
|
Account, on_delete=models.SET(get_deleted_account), related_name="opesgroup"
|
||||||
)
|
)
|
||||||
checkout = models.ForeignKey(
|
checkout = models.ForeignKey(
|
||||||
Checkout, on_delete=models.PROTECT, related_name="opesgroup"
|
Checkout, on_delete=models.PROTECT, related_name="opesgroup"
|
||||||
|
@ -681,7 +668,7 @@ class OperationGroup(models.Model):
|
||||||
comment = models.CharField(max_length=255, blank=True, default="")
|
comment = models.CharField(max_length=255, blank=True, default="")
|
||||||
valid_by = models.ForeignKey(
|
valid_by = models.ForeignKey(
|
||||||
Account,
|
Account,
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.SET(get_deleted_account),
|
||||||
related_name="+",
|
related_name="+",
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
|
@ -717,7 +704,7 @@ class Operation(models.Model):
|
||||||
# Optional
|
# Optional
|
||||||
article = models.ForeignKey(
|
article = models.ForeignKey(
|
||||||
Article,
|
Article,
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.SET_NULL,
|
||||||
related_name="operations",
|
related_name="operations",
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
|
@ -726,7 +713,7 @@ class Operation(models.Model):
|
||||||
article_nb = models.PositiveSmallIntegerField(blank=True, null=True, default=None)
|
article_nb = models.PositiveSmallIntegerField(blank=True, null=True, default=None)
|
||||||
canceled_by = models.ForeignKey(
|
canceled_by = models.ForeignKey(
|
||||||
Account,
|
Account,
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.SET(get_deleted_account),
|
||||||
related_name="+",
|
related_name="+",
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
|
@ -735,7 +722,7 @@ class Operation(models.Model):
|
||||||
canceled_at = models.DateTimeField(blank=True, null=True, default=None)
|
canceled_at = models.DateTimeField(blank=True, null=True, default=None)
|
||||||
addcost_for = models.ForeignKey(
|
addcost_for = models.ForeignKey(
|
||||||
Account,
|
Account,
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.SET(get_deleted_account),
|
||||||
related_name="addcosts",
|
related_name="addcosts",
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
|
|
|
@ -57,12 +57,20 @@ aside .heading .sub {
|
||||||
aside .buttons {
|
aside .buttons {
|
||||||
margin-left: -15px;
|
margin-left: -15px;
|
||||||
margin-right: -15px;
|
margin-right: -15px;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
aside .buttons > * {
|
aside .buttons > * {
|
||||||
flex: 0 1 auto !important;
|
flex: 0 1 auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aside .buttons > hr {
|
||||||
|
flex-basis: 100%;
|
||||||
|
height: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Aside - Text */
|
/* Aside - Text */
|
||||||
|
|
||||||
|
|
|
@ -23,11 +23,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.jconfirm .jconfirm-box .content-pane {
|
.jconfirm .jconfirm-box .content-pane {
|
||||||
margin:0 !important;
|
border-bottom:1px solid #ddd;
|
||||||
|
margin: 0px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jconfirm .jconfirm-box .content {
|
.jconfirm .jconfirm-box .content {
|
||||||
border-bottom:1px solid #ddd;
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jconfirm .jconfirm-box .content div.warning {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
margin: 5px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jconfirm .jconfirm-box input {
|
.jconfirm .jconfirm-box input {
|
||||||
|
@ -43,7 +51,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.jconfirm .jconfirm-box .buttons {
|
.jconfirm .jconfirm-box .buttons {
|
||||||
margin-top:-5px; /* j'arrive pas à voir pk y'a un espace au dessus sinon... */
|
margin-top:-6px; /* j'arrive pas à voir pk y'a un espace au dessus sinon... */
|
||||||
padding:0;
|
padding:0;
|
||||||
height:40px;
|
height:40px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ function KHistory(options={}) {
|
||||||
|
|
||||||
if (ope['type'] == 'purchase') {
|
if (ope['type'] == 'purchase') {
|
||||||
infos1 = ope['article_nb'];
|
infos1 = ope['article_nb'];
|
||||||
infos2 = ope['article__name'];
|
infos2 = ope['article__name'] ? ope['article__name'] : 'Article supprimé';
|
||||||
} else {
|
} else {
|
||||||
infos1 = parsed_amount.toFixed(2) + '€';
|
infos1 = parsed_amount.toFixed(2) + '€';
|
||||||
switch (ope['type']) {
|
switch (ope['type']) {
|
||||||
|
|
|
@ -20,12 +20,21 @@
|
||||||
<a class="btn btn-default" href="{% url 'kfet.article.update' article.pk %}">
|
<a class="btn btn-default" href="{% url 'kfet.article.update' article.pk %}">
|
||||||
<span class="glyphicon glyphicon-cog"></span><span>Éditer</span>
|
<span class="glyphicon glyphicon-cog"></span><span>Éditer</span>
|
||||||
</a>
|
</a>
|
||||||
|
{% if perms.kfet.delete_account %}
|
||||||
|
<button class="btn btn-default" id="button-delete">
|
||||||
|
<span class="glyphicon glyphicon-remove"></span><span>Supprimer</span>
|
||||||
|
</button>
|
||||||
|
<form method="post" action="{% url 'kfet.article.delete' article.pk %}" id="article-delete-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li>
|
<li>
|
||||||
<b>Prix:</b> <span>{{ article.price }}€</span>
|
<b>Prix:</b> <span>{{ article.price }}€</span>
|
||||||
<span data-toggle="tooltip" data-placement="right" class="glyphicon glyphicon-question-sign" title="Hors réduction COF"></span>
|
<span data-toggle="tooltip" data-placement="right" class="glyphicon glyphicon-question-sign"
|
||||||
|
title="Hors réduction COF"></span>
|
||||||
</li>
|
</li>
|
||||||
<li><b>Stock:</b> {{ article.stock }}</li>
|
<li><b>Stock:</b> {{ article.stock }}</li>
|
||||||
<li><b>En vente:</b> {{ article.is_sold|yesno|title }}</li>
|
<li><b>En vente:</b> {{ article.is_sold|yesno|title }}</li>
|
||||||
|
@ -129,6 +138,25 @@ $(document).ready(function() {
|
||||||
tabs_buttons.removeClass('focus');
|
tabs_buttons.removeClass('focus');
|
||||||
$(this).addClass('focus');
|
$(this).addClass('focus');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Delete button
|
||||||
|
$('#button-delete').click(function () {
|
||||||
|
$.confirm({
|
||||||
|
title: 'Confirmer la suppression',
|
||||||
|
content: `
|
||||||
|
<div class="warning">
|
||||||
|
<span class='glyphicon glyphicon-warning-sign'></span><span>Cette opération est irréversible !</span>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
backgroundDismiss: true,
|
||||||
|
animation: 'top',
|
||||||
|
closeAnimation: 'bottom',
|
||||||
|
keyboardEnabled: true,
|
||||||
|
confirm: function () {
|
||||||
|
$('#article-delete-form').submit();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,15 @@
|
||||||
<a class="btn btn-default" disabled>
|
<a class="btn btn-default" disabled>
|
||||||
<span class="glyphicon glyphicon-credit-card"></span><span>Créditer</span>
|
<span class="glyphicon glyphicon-credit-card"></span><span>Créditer</span>
|
||||||
</a>
|
</a>
|
||||||
|
{% if perms.kfet.delete_account %}
|
||||||
|
<hr>
|
||||||
|
<button class="btn btn-default" id="button-delete">
|
||||||
|
<span class="glyphicon glyphicon-remove"></span><span>Supprimer</span>
|
||||||
|
</button>
|
||||||
|
<form method="post" action="{% url 'kfet.account.delete' account.trigramme %}" id="account-delete-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text">
|
<div class="text">
|
||||||
|
@ -92,5 +101,24 @@ $( function() {
|
||||||
$(this).addClass('focus');
|
$(this).addClass('focus');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Delete button
|
||||||
|
$('#button-delete').click(function() {
|
||||||
|
$.confirm({
|
||||||
|
title: 'Confirmer la suppression',
|
||||||
|
content: `
|
||||||
|
<div class="warning">
|
||||||
|
<span class='glyphicon glyphicon-warning-sign'></span><span>Cette opération est irréversible !</span>
|
||||||
|
</div>
|
||||||
|
<span>Toutes les données associées à ce compte seront anonymisées.</span>
|
||||||
|
`,
|
||||||
|
backgroundDismiss: true,
|
||||||
|
animation: 'top',
|
||||||
|
closeAnimation: 'bottom',
|
||||||
|
keyboardEnabled: true,
|
||||||
|
confirm: function() {
|
||||||
|
$('#account-delete-form').submit();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -8,6 +8,8 @@ from django.test import Client, TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from .. import KFET_DELETED_TRIGRAMME
|
||||||
|
from ..auth import KFET_GENERIC_TRIGRAMME
|
||||||
from ..config import kfet_config
|
from ..config import kfet_config
|
||||||
from ..models import (
|
from ..models import (
|
||||||
Account,
|
Account,
|
||||||
|
@ -340,6 +342,61 @@ class AccountUpdateViewTests(ViewTestCaseMixin, TestCase):
|
||||||
self.assertForbiddenKfet(r)
|
self.assertForbiddenKfet(r)
|
||||||
|
|
||||||
|
|
||||||
|
class AccountDeleteViewTests(ViewTestCaseMixin, TestCase):
|
||||||
|
url_name = "kfet.account.delete"
|
||||||
|
url_kwargs = {"trigramme": "001"}
|
||||||
|
url_expected = "/k-fet/accounts/001/delete"
|
||||||
|
|
||||||
|
auth_user = "team1"
|
||||||
|
auth_forbidden = [None, "user", "team"]
|
||||||
|
http_methods = ["GET", "POST"]
|
||||||
|
with_liq = True
|
||||||
|
|
||||||
|
def get_users_extra(self):
|
||||||
|
return {
|
||||||
|
"user1": create_user("user1", "001"),
|
||||||
|
"team1": create_team("team1", "101", perms=["kfet.delete_account"]),
|
||||||
|
"trez": create_user("trez", "#13"),
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_get_405(self):
|
||||||
|
r = self.client.get(self.url)
|
||||||
|
self.assertEqual(r.status_code, 405)
|
||||||
|
|
||||||
|
def test_post_ok(self):
|
||||||
|
r = self.client.post(self.url, {})
|
||||||
|
self.assertRedirects(r, reverse("kfet.account"))
|
||||||
|
|
||||||
|
with self.assertRaises(Account.DoesNotExist):
|
||||||
|
self.accounts["user1"].refresh_from_db()
|
||||||
|
|
||||||
|
def test_protected_accounts(self):
|
||||||
|
for trigramme in ["LIQ", "#13", KFET_GENERIC_TRIGRAMME, KFET_DELETED_TRIGRAMME]:
|
||||||
|
if Account.objects.get(trigramme=trigramme).readable:
|
||||||
|
expected_code = 200
|
||||||
|
else:
|
||||||
|
expected_code = 403
|
||||||
|
r = self.client.post(
|
||||||
|
reverse(self.url_name, kwargs={"trigramme": trigramme}), {}
|
||||||
|
)
|
||||||
|
self.assertRedirects(
|
||||||
|
r,
|
||||||
|
reverse("kfet.account.read", kwargs={"trigramme": trigramme}),
|
||||||
|
target_status_code=expected_code,
|
||||||
|
)
|
||||||
|
# Devrait être redondant avec le précédent, mais on sait jamais
|
||||||
|
self.assertTrue(Account.objects.filter(trigramme=trigramme).exists())
|
||||||
|
|
||||||
|
def test_nonempty_accounts(self):
|
||||||
|
self.accounts["user1"].balance = 1
|
||||||
|
self.accounts["user1"].save()
|
||||||
|
|
||||||
|
r = self.client.post(self.url, {})
|
||||||
|
self.assertRedirects(r, reverse("kfet.account.read", kwargs=self.url_kwargs))
|
||||||
|
# Shouldn't throw an error
|
||||||
|
self.accounts["user1"].refresh_from_db()
|
||||||
|
|
||||||
|
|
||||||
class AccountGroupListViewTests(ViewTestCaseMixin, TestCase):
|
class AccountGroupListViewTests(ViewTestCaseMixin, TestCase):
|
||||||
url_name = "kfet.account.group"
|
url_name = "kfet.account.group"
|
||||||
url_expected = "/k-fet/accounts/groups"
|
url_expected = "/k-fet/accounts/groups"
|
||||||
|
@ -1288,6 +1345,42 @@ class ArticleUpdateViewTests(ViewTestCaseMixin, TestCase):
|
||||||
self.assertForbiddenKfet(r)
|
self.assertForbiddenKfet(r)
|
||||||
|
|
||||||
|
|
||||||
|
class ArticleDeleteViewTests(ViewTestCaseMixin, TestCase):
|
||||||
|
url_name = "kfet.article.delete"
|
||||||
|
|
||||||
|
auth_user = "team1"
|
||||||
|
auth_forbidden = [None, "user", "team"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url_kwargs(self):
|
||||||
|
return {"pk": self.article.pk}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url_expected(self):
|
||||||
|
return "/k-fet/articles/{}/delete".format(self.article.pk)
|
||||||
|
|
||||||
|
def get_users_extra(self):
|
||||||
|
return {"team1": create_team("team1", "101", perms=["kfet.delete_article"])}
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.category = ArticleCategory.objects.create(name="Category")
|
||||||
|
self.article = Article.objects.create(
|
||||||
|
name="Article", category=self.category, stock=5, price=Decimal("2.5")
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_redirects(self):
|
||||||
|
r = self.client.get(self.url)
|
||||||
|
self.assertRedirects(r, reverse("kfet.article.read", kwargs=self.url_kwargs))
|
||||||
|
|
||||||
|
def test_post_ok(self):
|
||||||
|
r = self.client.post(self.url, {})
|
||||||
|
self.assertRedirects(r, reverse("kfet.article"))
|
||||||
|
|
||||||
|
with self.assertRaises(Article.DoesNotExist):
|
||||||
|
self.article.refresh_from_db()
|
||||||
|
|
||||||
|
|
||||||
class ArticleStatSalesListViewTests(ViewTestCaseMixin, TestCase):
|
class ArticleStatSalesListViewTests(ViewTestCaseMixin, TestCase):
|
||||||
url_name = "kfet.article.stat.sales.list"
|
url_name = "kfet.article.stat.sales.list"
|
||||||
|
|
||||||
|
|
12
kfet/urls.py
12
kfet/urls.py
|
@ -57,6 +57,12 @@ urlpatterns = [
|
||||||
views.account_update,
|
views.account_update,
|
||||||
name="kfet.account.update",
|
name="kfet.account.update",
|
||||||
),
|
),
|
||||||
|
# Account - Delete
|
||||||
|
path(
|
||||||
|
"accounts/<trigramme:trigramme>/delete",
|
||||||
|
views.AccountDelete.as_view(),
|
||||||
|
name="kfet.account.delete",
|
||||||
|
),
|
||||||
# Account - Groups
|
# Account - Groups
|
||||||
path("accounts/groups", views.account_group, name="kfet.account.group"),
|
path("accounts/groups", views.account_group, name="kfet.account.group"),
|
||||||
path(
|
path(
|
||||||
|
@ -180,6 +186,12 @@ urlpatterns = [
|
||||||
teamkfet_required(views.ArticleUpdate.as_view()),
|
teamkfet_required(views.ArticleUpdate.as_view()),
|
||||||
name="kfet.article.update",
|
name="kfet.article.update",
|
||||||
),
|
),
|
||||||
|
# Article - Delete
|
||||||
|
path(
|
||||||
|
"articles/<int:pk>/delete",
|
||||||
|
views.ArticleDelete.as_view(),
|
||||||
|
name="kfet.article.delete",
|
||||||
|
),
|
||||||
# Article - Statistics
|
# Article - Statistics
|
||||||
path(
|
path(
|
||||||
"articles/<int:pk>/stat/sales/list",
|
"articles/<int:pk>/stat/sales/list",
|
||||||
|
|
|
@ -7,6 +7,7 @@ from urllib.parse import urlencode
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
from django.contrib.auth.models import Permission, User
|
from django.contrib.auth.models import Permission, User
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
|
@ -20,10 +21,10 @@ from django.utils import timezone
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views.generic import DetailView, FormView, ListView, TemplateView
|
from django.views.generic import DetailView, FormView, ListView, TemplateView
|
||||||
from django.views.generic.detail import BaseDetailView
|
from django.views.generic.detail import BaseDetailView
|
||||||
from django.views.generic.edit import CreateView, UpdateView
|
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||||
|
|
||||||
from gestioncof.models import CofProfile
|
from gestioncof.models import CofProfile
|
||||||
from kfet import consumers
|
from kfet import KFET_DELETED_TRIGRAMME, consumers
|
||||||
from kfet.config import kfet_config
|
from kfet.config import kfet_config
|
||||||
from kfet.decorators import teamkfet_required
|
from kfet.decorators import teamkfet_required
|
||||||
from kfet.forms import (
|
from kfet.forms import (
|
||||||
|
@ -78,6 +79,7 @@ from kfet.models import (
|
||||||
)
|
)
|
||||||
from kfet.statistic import ScaleMixin, WeekScale, last_stats_manifest
|
from kfet.statistic import ScaleMixin, WeekScale, last_stats_manifest
|
||||||
|
|
||||||
|
from .auth import KFET_GENERIC_TRIGRAMME
|
||||||
from .auth.views import ( # noqa
|
from .auth.views import ( # noqa
|
||||||
AccountGroupCreate,
|
AccountGroupCreate,
|
||||||
AccountGroupUpdate,
|
AccountGroupUpdate,
|
||||||
|
@ -467,6 +469,43 @@ def account_update(request, trigramme):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Account - Delete
|
||||||
|
|
||||||
|
|
||||||
|
class AccountDelete(PermissionRequiredMixin, DeleteView):
|
||||||
|
model = Account
|
||||||
|
slug_field = "trigramme"
|
||||||
|
slug_url_kwarg = "trigramme"
|
||||||
|
success_url = reverse_lazy("kfet.account")
|
||||||
|
success_message = "Compte supprimé avec succès !"
|
||||||
|
permission_required = "kfet.delete_account"
|
||||||
|
|
||||||
|
http_method_names = ["post"]
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
self.object = self.get_object()
|
||||||
|
if self.object.balance >= 0.01:
|
||||||
|
messages.error(
|
||||||
|
request,
|
||||||
|
"Impossible de supprimer un compte "
|
||||||
|
"avec une balance strictement positive !",
|
||||||
|
)
|
||||||
|
return redirect("kfet.account.read", self.object.trigramme)
|
||||||
|
|
||||||
|
if self.object.trigramme in [
|
||||||
|
"LIQ",
|
||||||
|
KFET_GENERIC_TRIGRAMME,
|
||||||
|
KFET_DELETED_TRIGRAMME,
|
||||||
|
"#13",
|
||||||
|
]:
|
||||||
|
messages.error(request, "Impossible de supprimer un trigramme protégé !")
|
||||||
|
return redirect("kfet.account.read", self.object.trigramme)
|
||||||
|
|
||||||
|
# SuccessMessageMixin does not work with DeleteView, see :
|
||||||
|
# https://code.djangoproject.com/ticket/21926
|
||||||
|
messages.success(request, self.success_message)
|
||||||
|
return super().delete(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AccountNegativeList(ListView):
|
class AccountNegativeList(ListView):
|
||||||
queryset = AccountNegative.objects.select_related(
|
queryset = AccountNegative.objects.select_related(
|
||||||
|
@ -837,6 +876,20 @@ class ArticleUpdate(SuccessMessageMixin, UpdateView):
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
|
class ArticleDelete(PermissionRequiredMixin, DeleteView):
|
||||||
|
model = Article
|
||||||
|
success_url = reverse_lazy("kfet.article")
|
||||||
|
success_message = "Article supprimé avec succès !"
|
||||||
|
permission_required = "kfet.delete_article"
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
return redirect("kfet.article.read", self.kwargs.get(self.pk_url_kwarg))
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
messages.success(request, self.success_message)
|
||||||
|
return super().delete(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
# K-Psul
|
# K-Psul
|
||||||
# -----
|
# -----
|
||||||
|
|
Loading…
Add table
Reference in a new issue