mirror of
https://framagit.org/la-chariotte/la-chariotte.git
synced 2025-05-02 20:01:51 +02:00
generate a 6 digit long unique code for each grouped order
This commit is contained in:
parent
9e52ded095
commit
2083142d47
7 changed files with 91 additions and 2 deletions
45
la_chariotte/order/migrations/0025_groupedorder_code.py
Normal file
45
la_chariotte/order/migrations/0025_groupedorder_code.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
# Generated by Django 4.2.1 on 2023-08-08 09:20
|
||||
|
||||
from django.db import migrations, models
|
||||
import base36
|
||||
import random
|
||||
|
||||
|
||||
def create_code_from_pk(pk):
|
||||
"""When a grouped order is created, we compute a unique code that will be used in url path
|
||||
How we generate this code :
|
||||
1. The instance pk, written in base36 (max 5 digits for now - we assume that there will not be more than 60466175 grouped orders)
|
||||
2. A random int written in base36 (5 digits long)
|
||||
3. Only the 6 first digits of this string
|
||||
The use of pk in the beginning of the string guarantees the uniqueness, and the random part makes that we cannot guess the url path.
|
||||
"""
|
||||
base_36_pk = base36.dumps(pk)
|
||||
random_string = base36.dumps(random.randint(1727605,60466175)) # generates a 5 digits long string
|
||||
return f"{base_36_pk}{random_string}"
|
||||
|
||||
def set_code_default(apps, schema_editor):
|
||||
"""Provides a default code to existing grouped orders during migration"""
|
||||
GroupedOrder = apps.get_model("order","GroupedOrder")
|
||||
for grouped_order in GroupedOrder.objects.all().iterator():
|
||||
grouped_order.code = create_code_from_pk(grouped_order.pk)
|
||||
grouped_order.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("order", "0024_alter_item_options"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="groupedorder",
|
||||
name="code",
|
||||
field=models.CharField(auto_created=True, null=True),
|
||||
),
|
||||
migrations.RunPython(set_code_default),
|
||||
migrations.AlterField(
|
||||
model_name="groupedorder",
|
||||
name="code",
|
||||
field=models.CharField(auto_created=True),
|
||||
),
|
||||
]
|
|
@ -1,3 +1,6 @@
|
|||
import random
|
||||
|
||||
import base36
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
|
@ -5,6 +8,8 @@ from django.utils import timezone
|
|||
|
||||
from la_chariotte.settings import AUTH_USER_MODEL
|
||||
|
||||
CODE_LENGTH = 6
|
||||
|
||||
|
||||
class GroupedOrder(models.Model):
|
||||
name = models.CharField(
|
||||
|
@ -20,6 +25,21 @@ class GroupedOrder(models.Model):
|
|||
)
|
||||
description = models.TextField("Description", null=True, blank=True)
|
||||
total_price = models.DecimalField(max_digits=10, decimal_places=2, default=0)
|
||||
code = models.CharField(auto_created=True)
|
||||
|
||||
def create_code_from_pk(self):
|
||||
"""When a grouped order is created, we compute a unique code that will be used in url path
|
||||
How we generate this code :
|
||||
1. The instance pk, written in base36 (max 5 digits for now - we assume that there will not be more than 60466175 grouped orders)
|
||||
2. A random int written in base36 (5 digits long)
|
||||
3. Only the 6 first digits of this string
|
||||
The use of pk in the beginning of the string guarantees the uniqueness, and the random part makes that we cannot guess the url path.
|
||||
"""
|
||||
base_36_pk = base36.dumps(self.pk)
|
||||
random_string = base36.dumps(
|
||||
random.randint(pow(36, CODE_LENGTH - 2), pow(36, CODE_LENGTH - 1) - 1)
|
||||
) # generates a 5 digits long string
|
||||
self.code = f"{base_36_pk}{random_string}"[:CODE_LENGTH]
|
||||
|
||||
def compute_total_price(self):
|
||||
price = 0
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import datetime
|
||||
|
||||
import pytest
|
||||
from django.contrib import auth
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from la_chariotte.order.models import GroupedOrder, Item
|
||||
from la_chariotte.order.models import CODE_LENGTH, GroupedOrder, Item
|
||||
from la_chariotte.order.tests.utils import create_grouped_order
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
class TestGroupedOrderModel:
|
||||
|
@ -124,6 +128,15 @@ class TestGroupedOrderModel:
|
|||
"La date de livraison ne doit pas être dans le passé" in response.content.decode()
|
||||
assert GroupedOrder.objects.count() == 0
|
||||
|
||||
def test_create_unique_code_from_pk(self, client_log):
|
||||
grouped_order = create_grouped_order(
|
||||
days_before_delivery_date=5,
|
||||
days_before_deadline=2,
|
||||
name="future",
|
||||
orga_user=auth.get_user(client_log),
|
||||
)
|
||||
assert len(grouped_order.code) == CODE_LENGTH
|
||||
|
||||
|
||||
class TestItemModel:
|
||||
"""Tests for Item model"""
|
||||
|
|
|
@ -791,6 +791,7 @@ class TestGroupedOrderCreateView:
|
|||
assert response.status_code == 302
|
||||
assert response.url.endswith("gerer-produits")
|
||||
assert models.GroupedOrder.objects.count() == 1
|
||||
assert models.GroupedOrder.objects.first().code != ""
|
||||
|
||||
def test_create_grouped_order__anonymous_user(self, client):
|
||||
create_gorder_url = reverse("order:create_grouped_order")
|
||||
|
|
|
@ -18,9 +18,11 @@ def create_grouped_order(
|
|||
"""
|
||||
date = timezone.now().date() + datetime.timedelta(days=days_before_delivery_date)
|
||||
deadline = timezone.now() + datetime.timedelta(days=days_before_deadline)
|
||||
return models.GroupedOrder.objects.create(
|
||||
grouped_order = models.GroupedOrder.objects.create(
|
||||
name=name, orga=orga_user, delivery_date=date, deadline=deadline
|
||||
)
|
||||
grouped_order.create_code_from_pk()
|
||||
return grouped_order
|
||||
|
||||
|
||||
def order_items_in_grouped_order(grouped_order):
|
||||
|
|
|
@ -122,6 +122,12 @@ class GroupedOrderCreateView(LoginRequiredMixin, generic.CreateView):
|
|||
kwargs["user"] = self.request.user
|
||||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
"""If the form is valid, generate a unique code and save"""
|
||||
self.object = form.save()
|
||||
self.object.create_code_from_pk()
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class GroupedOrderUpdateView(UserPassesTestMixin, generic.UpdateView):
|
||||
"""View for updating a grouped order"""
|
||||
|
|
|
@ -13,6 +13,8 @@ asn1crypto==1.5.1
|
|||
# oscrypto
|
||||
# pyhanko
|
||||
# pyhanko-certvalidator
|
||||
base36==0.1.1
|
||||
# à la main
|
||||
certifi==2023.5.7
|
||||
# via
|
||||
# requests
|
||||
|
|
Loading…
Reference in a new issue