Files
2026-09-04 13:05:54 +03:30

93 lines
3.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django import forms
from django.utils.translation import gettext_lazy as _
from apps.account.models import User
def normalize_iran_phone(raw: str) -> str:
"""۰۹۱۲…، +۹۸۹۱۲…، ۰۰۹۸۹۱۲… و ارقام فارسی را به شکلِ یکّه‌ی 09xxxxxxxxx می‌برد.
ادمین شماره را از هرجایی کپی می‌کند (پیامک، اکسل، پیام‌رسان)؛ اگر شکلِ
ورودی را نرمال نکنیم، «کاربر پیدا نشد» می‌گیرد در حالی که کاربر هست.
"""
digits = {
"۰": "0", "۱": "1", "۲": "2", "۳": "3", "۴": "4",
"۵": "5", "۶": "6", "۷": "7", "۸": "8", "۹": "9",
"٠": "0", "١": "1", "٢": "2", "٣": "3", "٤": "4",
"٥": "5", "٦": "6", "٧": "7", "٨": "8", "٩": "9",
}
value = "".join(digits.get(ch, ch) for ch in (raw or "").strip())
value = "".join(ch for ch in value if ch.isdigit() or ch == "+")
value = value.lstrip("+")
if value.startswith("0098"):
value = value[4:]
elif value.startswith("98") and len(value) == 12:
value = value[2:]
if value.startswith("9") and len(value) == 10:
value = "0" + value
return value
class GemGiftForm(forms.Form):
"""هدیه‌دادنِ جم به یک یا چند شماره — از پنل ادمین.
عمداً روی *شماره* کار می‌کند نه روی انتخابِ کاربر از لیست: ادمین معمولا
شماره را دارد (از پشتیبانی، از یک کمپین)، نه شناسه‌ی کاربر را.
"""
phones = forms.CharField(
label=_("شماره‌ها"),
widget=forms.Textarea(attrs={"rows": 5, "dir": "ltr"}),
help_text=_(
"هر شماره در یک خط (یا با کاما جدا کن). "
"شکل‌های 09123456789 و +989123456789 هر دو قبول است."
),
)
amount = forms.IntegerField(
label=_("تعداد جم"),
min_value=1,
help_text=_("به هر شماره همین مقدار جم اضافه می‌شود."),
)
note = forms.CharField(
label=_("علت / یادداشت"),
max_length=255,
required=False,
help_text=_("در تاریخچه‌ی تراکنش‌های جم ذخیره می‌شود — مثلا «جبران خطای پرداخت»."),
)
create_missing = forms.BooleanField(
label=_("اگر کاربر وجود ندارد، ساخته شود"),
required=False,
help_text=_(
"برای هدیه‌ی پیش از ثبت‌نام. کاربر با همان شماره ساخته می‌شود و "
"جم موقع اولین ورودش آماده است."
),
)
def clean_phones(self) -> list[str]:
raw = self.cleaned_data["phones"].replace(",", "\n")
numbers, seen = [], set()
invalid = []
for line in raw.splitlines():
if not line.strip():
continue
phone = normalize_iran_phone(line)
if len(phone) != 11 or not phone.startswith("09"):
invalid.append(line.strip())
continue
if phone not in seen:
seen.add(phone)
numbers.append(phone)
if invalid:
raise forms.ValidationError(
_("این شماره‌ها معتبر نیستند: %(bad)s") % {"bad": "، ".join(invalid)}
)
if not numbers:
raise forms.ValidationError(_("حداقل یک شماره وارد کن."))
return numbers
def existing_and_missing(self) -> tuple[list[User], list[str]]:
phones = self.cleaned_data["phones"]
users = list(User.objects.filter(phone__in=phones))
found = {u.phone for u in users}
return users, [p for p in phones if p not in found]