mirror of
				https://github.com/ae-utbm/sith.git
				synced 2025-11-04 02:53:06 +00:00 
			
		
		
		
	Merge pull request #499 from ae-utbm/unify-account-creation
Unify account id creation
This commit is contained in:
		
							
								
								
									
										21
									
								
								counter/migrations/0020_auto_20221215_1709.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								counter/migrations/0020_auto_20221215_1709.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					# Generated by Django 3.2.16 on 2022-12-15 16:09
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import accounting.models
 | 
				
			||||||
 | 
					from django.db import migrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ("counter", "0019_billinginfo"),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name="customer",
 | 
				
			||||||
 | 
					            name="amount",
 | 
				
			||||||
 | 
					            field=accounting.models.CurrencyField(
 | 
				
			||||||
 | 
					                decimal_places=2, default=0, max_digits=12, verbose_name="amount"
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -21,6 +21,9 @@
 | 
				
			|||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
 | 
					# Place - Suite 330, Boston, MA 02111-1307, USA.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					from __future__ import annotations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from typing import Tuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from django.db.models.functions import Length
 | 
					from django.db.models.functions import Length
 | 
				
			||||||
@@ -57,7 +60,7 @@ class Customer(models.Model):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE)
 | 
					    user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE)
 | 
				
			||||||
    account_id = models.CharField(_("account id"), max_length=10, unique=True)
 | 
					    account_id = models.CharField(_("account id"), max_length=10, unique=True)
 | 
				
			||||||
    amount = CurrencyField(_("amount"))
 | 
					    amount = CurrencyField(_("amount"), default=0)
 | 
				
			||||||
    recorded_products = models.IntegerField(_("recorded product"), default=0)
 | 
					    recorded_products = models.IntegerField(_("recorded product"), default=0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
@@ -94,12 +97,27 @@ class Customer(models.Model):
 | 
				
			|||||||
        ) < timedelta(days=90)
 | 
					        ) < timedelta(days=90)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def new_for_user(cls, user: User):
 | 
					    def get_or_create(cls, user: User) -> Tuple[Customer, bool]:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Create a new Customer instance for the user given in parameter without saving it
 | 
					        Work in pretty much the same way as the usual get_or_create method,
 | 
				
			||||||
        The account if is automatically generated and the amount set at 0
 | 
					        but with the default field replaced by some under the hood.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If the user has an account, return it as is.
 | 
				
			||||||
 | 
					        Else create a new account with no money on it and a new unique account id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Example : ::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            user = User.objects.get(pk=1)
 | 
				
			||||||
 | 
					            account, created = Customer.get_or_create(user)
 | 
				
			||||||
 | 
					            if created:
 | 
				
			||||||
 | 
					                print(f"created a new account with id {account.id}")
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                print(f"user has already an account, with {account.id} € on it"
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        # account_id are number with a letter appended
 | 
					        if hasattr(user, "customer"):
 | 
				
			||||||
 | 
					            return user.customer, False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # account_id are always a number with a letter appended
 | 
				
			||||||
        account_id = (
 | 
					        account_id = (
 | 
				
			||||||
            Customer.objects.order_by(Length("account_id"), "account_id")
 | 
					            Customer.objects.order_by(Length("account_id"), "account_id")
 | 
				
			||||||
            .values("account_id")
 | 
					            .values("account_id")
 | 
				
			||||||
@@ -107,14 +125,19 @@ class Customer(models.Model):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        if account_id is None:
 | 
					        if account_id is None:
 | 
				
			||||||
            # legacy from the old site
 | 
					            # legacy from the old site
 | 
				
			||||||
            return cls(user=user, account_id="1504a", amount=0)
 | 
					            account = cls.objects.create(user=user, account_id="1504a")
 | 
				
			||||||
        account_id = account_id["account_id"]
 | 
					            return account, True
 | 
				
			||||||
        num = int(account_id[:-1])
 | 
					 | 
				
			||||||
        while Customer.objects.filter(account_id=account_id).exists():
 | 
					 | 
				
			||||||
            num += 1
 | 
					 | 
				
			||||||
            account_id = str(num) + random.choice(string.ascii_lowercase)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return cls(user=user, account_id=account_id, amount=0)
 | 
					        account_id = account_id["account_id"]
 | 
				
			||||||
 | 
					        account_num = int(account_id[:-1])
 | 
				
			||||||
 | 
					        while Customer.objects.filter(account_id=account_id).exists():
 | 
				
			||||||
 | 
					            # when entering the first iteration, we are using an already existing account id
 | 
				
			||||||
 | 
					            # so the loop should always execute at least one time
 | 
				
			||||||
 | 
					            account_num += 1
 | 
				
			||||||
 | 
					            account_id = f"{account_num}{random.choice(string.ascii_lowercase)}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        account = cls.objects.create(user=user, account_id=account_id)
 | 
				
			||||||
 | 
					        return account, True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def save(self, allow_negative=False, is_selling=False, *args, **kwargs):
 | 
					    def save(self, allow_negative=False, is_selling=False, *args, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.test import TestCase
 | 
					from django.test import TestCase
 | 
				
			||||||
from django.urls import reverse
 | 
					from django.urls import reverse
 | 
				
			||||||
@@ -754,18 +755,30 @@ class StudentCardTest(TestCase):
 | 
				
			|||||||
        self.assertEqual(response.status_code, 403)
 | 
					        self.assertEqual(response.status_code, 403)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AccountIdTest(TestCase):
 | 
					class CustomerAccountIdTest(TestCase):
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        user_a = User.objects.create(username="a", password="plop", email="a.a@a.fr")
 | 
					        self.user_a = User.objects.create(
 | 
				
			||||||
 | 
					            username="a", password="plop", email="a.a@a.fr"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        user_b = User.objects.create(username="b", password="plop", email="b.b@b.fr")
 | 
					        user_b = User.objects.create(username="b", password="plop", email="b.b@b.fr")
 | 
				
			||||||
        user_c = User.objects.create(username="c", password="plop", email="c.c@c.fr")
 | 
					        user_c = User.objects.create(username="c", password="plop", email="c.c@c.fr")
 | 
				
			||||||
        Customer.objects.create(user=user_a, amount=0, account_id="1111a")
 | 
					        Customer.objects.create(user=self.user_a, amount=10, account_id="1111a")
 | 
				
			||||||
        Customer.objects.create(user=user_b, amount=0, account_id="9999z")
 | 
					        Customer.objects.create(user=user_b, amount=0, account_id="9999z")
 | 
				
			||||||
        Customer.objects.create(user=user_c, amount=0, account_id="12345f")
 | 
					        Customer.objects.create(user=user_c, amount=0, account_id="12345f")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_create_customer(self):
 | 
					    def test_create_customer(self):
 | 
				
			||||||
        user_d = User.objects.create(username="d", password="plop")
 | 
					        user_d = User.objects.create(username="d", password="plop")
 | 
				
			||||||
        customer_d = Customer.new_for_user(user_d)
 | 
					        customer, created = Customer.get_or_create(user_d)
 | 
				
			||||||
        customer_d.save()
 | 
					        account_id = customer.account_id
 | 
				
			||||||
        number = customer_d.account_id[:-1]
 | 
					        number = account_id[:-1]
 | 
				
			||||||
 | 
					        self.assertTrue(created)
 | 
				
			||||||
        self.assertEqual(number, "12346")
 | 
					        self.assertEqual(number, "12346")
 | 
				
			||||||
 | 
					        self.assertEqual(6, len(account_id))
 | 
				
			||||||
 | 
					        self.assertIn(account_id[-1], string.ascii_lowercase)
 | 
				
			||||||
 | 
					        self.assertEqual(0, customer.amount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_existing_account(self):
 | 
				
			||||||
 | 
					        account, created = Customer.get_or_create(self.user_a)
 | 
				
			||||||
 | 
					        self.assertFalse(created)
 | 
				
			||||||
 | 
					        self.assertEqual(account.account_id, "1111a")
 | 
				
			||||||
 | 
					        self.assertEqual(10, account.amount)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1792,11 +1792,7 @@ def create_billing_info(request, user_id):
 | 
				
			|||||||
    if user.id != user_id and not user.has_perm("counter:add_billinginfo"):
 | 
					    if user.id != user_id and not user.has_perm("counter:add_billinginfo"):
 | 
				
			||||||
        raise PermissionDenied()
 | 
					        raise PermissionDenied()
 | 
				
			||||||
    user = get_object_or_404(User, pk=user_id)
 | 
					    user = get_object_or_404(User, pk=user_id)
 | 
				
			||||||
    if not hasattr(user, "customer"):
 | 
					    customer, _ = Customer.get_or_create(user)
 | 
				
			||||||
        customer = Customer.new_for_user(user)
 | 
					 | 
				
			||||||
        customer.save()
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        customer = get_object_or_404(Customer, user_id=user_id)
 | 
					 | 
				
			||||||
    BillingInfo.objects.create(customer=customer)
 | 
					    BillingInfo.objects.create(customer=customer)
 | 
				
			||||||
    return __manage_billing_info_req(request, user_id, True)
 | 
					    return __manage_billing_info_req(request, user_id, True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -245,12 +245,13 @@ class Invoice(models.Model):
 | 
				
			|||||||
    def validate(self):
 | 
					    def validate(self):
 | 
				
			||||||
        if self.validated:
 | 
					        if self.validated:
 | 
				
			||||||
            raise DataError(_("Invoice already validated"))
 | 
					            raise DataError(_("Invoice already validated"))
 | 
				
			||||||
 | 
					        customer, created = Customer.get_or_create(user=self.user)
 | 
				
			||||||
        eboutic = Counter.objects.filter(type="EBOUTIC").first()
 | 
					        eboutic = Counter.objects.filter(type="EBOUTIC").first()
 | 
				
			||||||
        for i in self.items.all():
 | 
					        for i in self.items.all():
 | 
				
			||||||
            if i.type_id == settings.SITH_COUNTER_PRODUCTTYPE_REFILLING:
 | 
					            if i.type_id == settings.SITH_COUNTER_PRODUCTTYPE_REFILLING:
 | 
				
			||||||
                new = Refilling(
 | 
					                new = Refilling(
 | 
				
			||||||
                    counter=eboutic,
 | 
					                    counter=eboutic,
 | 
				
			||||||
                    customer=self.user.customer,
 | 
					                    customer=customer,
 | 
				
			||||||
                    operator=self.user,
 | 
					                    operator=self.user,
 | 
				
			||||||
                    amount=i.product_unit_price * i.quantity,
 | 
					                    amount=i.product_unit_price * i.quantity,
 | 
				
			||||||
                    payment_method="CARD",
 | 
					                    payment_method="CARD",
 | 
				
			||||||
@@ -266,7 +267,7 @@ class Invoice(models.Model):
 | 
				
			|||||||
                    club=product.club,
 | 
					                    club=product.club,
 | 
				
			||||||
                    product=product,
 | 
					                    product=product,
 | 
				
			||||||
                    seller=self.user,
 | 
					                    seller=self.user,
 | 
				
			||||||
                    customer=self.user.customer,
 | 
					                    customer=customer,
 | 
				
			||||||
                    unit_price=i.product_unit_price,
 | 
					                    unit_price=i.product_unit_price,
 | 
				
			||||||
                    quantity=i.quantity,
 | 
					                    quantity=i.quantity,
 | 
				
			||||||
                    payment_method="CARD",
 | 
					                    payment_method="CARD",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from datetime import date, timedelta
 | 
					from datetime import date, timedelta
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from django.utils import timezone
 | 
					 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.core.exceptions import ValidationError
 | 
					from django.core.exceptions import ValidationError
 | 
				
			||||||
@@ -101,8 +100,8 @@ class Subscription(models.Model):
 | 
				
			|||||||
        super(Subscription, self).save()
 | 
					        super(Subscription, self).save()
 | 
				
			||||||
        from counter.models import Customer
 | 
					        from counter.models import Customer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not Customer.objects.filter(user=self.member).exists():
 | 
					        _, created = Customer.get_or_create(self.member)
 | 
				
			||||||
            Customer.new_for_user(self.member).save()
 | 
					        if created:
 | 
				
			||||||
            form = PasswordResetForm({"email": self.member.email})
 | 
					            form = PasswordResetForm({"email": self.member.email})
 | 
				
			||||||
            if form.is_valid():
 | 
					            if form.is_valid():
 | 
				
			||||||
                form.save(
 | 
					                form.save(
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user