diff --git a/counter/migrations/0040_product_clic_limit.py b/counter/migrations/0040_product_clic_limit.py
index b923520e..7f0b7912 100644
--- a/counter/migrations/0040_product_clic_limit.py
+++ b/counter/migrations/0040_product_clic_limit.py
@@ -15,7 +15,7 @@ class Migration(migrations.Migration):
blank=True,
help_text=(
"If a limit is set, the product won't be purchasable "
- "anymore once the latter is reached."
+ "anymore on the eboutic once the latter is reached."
),
null=True,
verbose_name="clic limit",
diff --git a/counter/migrations/0041_alter_billinginfo_country_and_more.py b/counter/migrations/0041_alter_billinginfo_country_and_more.py
new file mode 100644
index 00000000..c713546f
--- /dev/null
+++ b/counter/migrations/0041_alter_billinginfo_country_and_more.py
@@ -0,0 +1,26 @@
+# Generated by Django 5.2.14 on 2026-06-02 10:45
+
+import django_countries.fields
+import phonenumber_field.modelfields
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+ dependencies = [("counter", "0040_product_clic_limit")]
+
+ operations = [
+ migrations.AlterField(
+ model_name="billinginfo",
+ name="country",
+ field=django_countries.fields.CountryField(
+ max_length=2, verbose_name="Country"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="billinginfo",
+ name="phone_number",
+ field=phonenumber_field.modelfields.PhoneNumberField(
+ max_length=128, region=None, verbose_name="Phone number"
+ ),
+ ),
+ ]
diff --git a/counter/models.py b/counter/models.py
index 6e87fb25..1907d2fb 100644
--- a/counter/models.py
+++ b/counter/models.py
@@ -228,15 +228,8 @@ class BillingInfo(models.Model):
address_2 = models.CharField(_("Address 2"), max_length=50, blank=True, null=True)
zip_code = models.CharField(_("Zip code"), max_length=16) # code postal
city = models.CharField(_("City"), max_length=50)
- country = CountryField(blank_label=_("Country"))
-
- # This table was created during the A22 semester.
- # However, later on, CA asked for the phone number to be added to the billing info.
- # As the table was already created, this new field had to be nullable,
- # even tough it is required by the bank and shouldn't be null.
- # If one day there is no null phone number remaining,
- # please make the field non-nullable.
- phone_number = PhoneNumberField(_("Phone number"), null=True, blank=False)
+ country = CountryField(_("Country"))
+ phone_number = PhoneNumberField(_("Phone number"))
def __str__(self):
return f"{self.first_name} {self.last_name}"
diff --git a/eboutic/models.py b/eboutic/models.py
index a8ab547f..83034e4c 100644
--- a/eboutic/models.py
+++ b/eboutic/models.py
@@ -16,7 +16,6 @@ from __future__ import annotations
import hmac
from datetime import datetime
-from enum import Enum
from typing import Self
from dict2xml import dict2xml
@@ -40,30 +39,6 @@ from counter.models import (
)
-class BillingInfoState(Enum):
- VALID = 1
- EMPTY = 2
- MISSING_PHONE_NUMBER = 3
-
- @classmethod
- def from_model(cls, info: BillingInfo | None) -> BillingInfoState:
- if info is None:
- return cls.EMPTY
- for attr in [
- "first_name",
- "last_name",
- "address_1",
- "zip_code",
- "city",
- "country",
- ]:
- if getattr(info, attr) == "":
- return cls.EMPTY
- if info.phone_number is None:
- return cls.MISSING_PHONE_NUMBER
- return cls.VALID
-
-
class Basket(models.Model):
"""Basket is built when the user connects to an eboutic page."""
@@ -162,11 +137,7 @@ class Basket(models.Model):
if self.is_expired:
raise ValueError("This method cannot be called on an expired basket.")
customer = user.customer
- if (
- not hasattr(user.customer, "billing_infos")
- or BillingInfoState.from_model(user.customer.billing_infos)
- != BillingInfoState.VALID
- ):
+ if not hasattr(user.customer, "billing_infos"):
raise BillingInfo.DoesNotExist
cart = {
"shoppingcart": {"total": {"totalQuantity": min(self.items.count(), 99)}}
diff --git a/eboutic/templates/eboutic/eboutic_billing_info.jinja b/eboutic/templates/eboutic/eboutic_billing_info.jinja
index df8152ef..e05e6de4 100644
--- a/eboutic/templates/eboutic/eboutic_billing_info.jinja
+++ b/eboutic/templates/eboutic/eboutic_billing_info.jinja
@@ -24,7 +24,7 @@
x-cloak
>
{% csrf_token %}
- {{ form.as_p() }}
+ {{ form }}
HttpResponse:
class BillingInfoFormFragment(
LoginRequiredMixin, FragmentMixin, SuccessMessageMixin, UpdateView
):
- """Update billing info"""
+ """Update or create billing info"""
model = BillingInfo
form_class = BillingInfoForm
@@ -218,26 +218,15 @@ class BillingInfoFormFragment(
def get_context_data(self, **kwargs):
kwargs = super().get_context_data(**kwargs)
- kwargs["billing_infos_state"] = BillingInfoState.from_model(self.object)
kwargs["action"] = reverse("eboutic:billing_infos")
- match BillingInfoState.from_model(self.object):
- case BillingInfoState.EMPTY:
- messages.warning(
- self.request,
- _(
- "You must fill your billing infos if you want to pay with your credit card"
- ),
- )
- case BillingInfoState.MISSING_PHONE_NUMBER:
- messages.warning(
- self.request,
- _(
- "The Crédit Agricole changed its policy related to the billing "
- + "information that must be provided in order to pay with a credit card. "
- + "If you want to pay with your credit card, you must add a phone number "
- + "to the data you already provided.",
- ),
- )
+ if not self.object:
+ messages.warning(
+ self.request,
+ _(
+ "You must fill your billing infos "
+ "if you want to pay with your credit card"
+ ),
+ )
return kwargs
def get_success_url(self, **kwargs):
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index b270e6e4..722d7921 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -4511,18 +4511,6 @@ msgstr ""
"Vous devez renseigner vos coordonnées de facturation si vous voulez payer "
"par carte bancaire"
-#: eboutic/views.py
-msgid ""
-"The Crédit Agricole changed its policy related to the billing information "
-"that must be provided in order to pay with a credit card. If you want to pay "
-"with your credit card, you must add a phone number to the data you already "
-"provided."
-msgstr ""
-"Le Crédit Agricole a changé sa politique relative aux informations à "
-"fournir pour effectuer un paiement par carte bancaire. De ce fait, si vous "
-"souhaitez payer par carte, vous devez rajouter un numéro de téléphone aux "
-"données que vous aviez déjà fourni."
-
#: eboutic/views.py
msgid "Basket expired"
msgstr "Panier expiré"
diff --git a/sith/settings.py b/sith/settings.py
index 21d4f11f..ce872c7d 100644
--- a/sith/settings.py
+++ b/sith/settings.py
@@ -115,6 +115,7 @@ INSTALLED_APPS = (
"django_jinja",
"ninja_extra",
"haystack",
+ "django_countries",
"django_celery_results",
"django_celery_beat",
"captcha",
@@ -294,7 +295,11 @@ USE_TZ = True
LOCALE_PATHS = [BASE_DIR / "locale"]
+# for PhoneNumberField
PHONENUMBER_DEFAULT_REGION = "FR"
+# for CountryField
+COUNTRIES_FIRST = ["FR", "CH", "DE"]
+COUNTRIES_FIRST_BREAK = "───────────"
# Medias
MEDIA_URL = "/data/"