diff --git a/_base/settings.py b/_base/settings.py index e9079ca..6283ccf 100644 --- a/_base/settings.py +++ b/_base/settings.py @@ -157,15 +157,15 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' JAZZMIN_SETTINGS = { # title of the window (Will default to current_admin_site.site_title if absent or None) - "site_title": "سامانه شفافیت", + "site_title": "کنتور پلاس", # Title on the login screen (19 chars max) (defaults to current_admin_site.site_header if absent or None) - "site_header": "سامانه شفافیت", + "site_header": "کنتور پلاس", # Title on the brand (19 chars max) (defaults to current_admin_site.site_header if absent or None) - "site_brand": "سامانه شفافیت", + "site_brand": "کنتور پلاس", # Welcome text on the login screen - "welcome_sign": "به سامانه شفافیت خوش آمدید", + "welcome_sign": "به کنتور پلاس خوش آمدید", # Copyright on the footer - "copyright": "سامانه شفافیت", + "copyright": "کنتور پلاس", # Logo to use for your site, must be present in static files, used for brand on top left # "site_logo": "../static/dist/img/iconlogo.png", # Relative paths to custom CSS/JS scripts (must be present in static files) diff --git a/_helpers/utils.py b/_helpers/utils.py index a7adccb..92f24b4 100644 --- a/_helpers/utils.py +++ b/_helpers/utils.py @@ -192,4 +192,122 @@ def normalize_size(size: int) -> str: return f"{int(size_mb)} MB" if size_mb.is_integer() else f"{size_mb:.1f} MB" else: size_gb = size / (1024 * 1024 * 1024) - return f"{int(size_gb)} GB" if size_gb.is_integer() else f"{size_gb:.1f} GB" \ No newline at end of file + return f"{int(size_gb)} GB" if size_gb.is_integer() else f"{size_gb:.1f} GB" + + +def number_to_persian_words(number): + """ + تبدیل عدد به حروف فارسی + مثال: 12345 -> دوازده هزار و سیصد و چهل و پنج + """ + try: + # تبدیل به عدد صحیح (در صورت نیاز) + from decimal import Decimal + if isinstance(number, Decimal): + number = int(number) + elif isinstance(number, float): + number = int(number) + elif isinstance(number, str): + number = int(float(number.replace(',', ''))) + + if number == 0: + return "صفر" + + if number < 0: + return "منفی " + number_to_persian_words(abs(number)) + + # اعداد یک رقمی + ones = [ + "", "یک", "دو", "سه", "چهار", "پنج", "شش", "هفت", "هشت", "نه" + ] + + # اعداد ده تا نوزده + teens = [ + "ده", "یازده", "دوازده", "سیزده", "چهارده", "پانزده", + "شانزده", "هفده", "هجده", "نوزده" + ] + + # اعداد بیست تا نود + tens = [ + "", "", "بیست", "سی", "چهل", "پنجاه", "شصت", "هفتاد", "هشتاد", "نود" + ] + + # اعداد صد تا نهصد + hundreds = [ + "", "یکصد", "دویست", "سیصد", "چهارصد", "پانصد", + "ششصد", "هفتصد", "هشتصد", "نهصد" + ] + + # مراتب بزرگتر + scale = [ + "", "هزار", "میلیون", "میلیارد", "بیلیون", "بیلیارد" + ] + + def convert_group(num): + """تبدیل گروه سه رقمی به حروف""" + if num == 0: + return "" + + result = [] + + # صدها + h = num // 100 + if h > 0: + result.append(hundreds[h]) + + # دهگان و یکان + remainder = num % 100 + + if remainder >= 10 and remainder < 20: + # اعداد 10 تا 19 + result.append(teens[remainder - 10]) + else: + # دهگان + t = remainder // 10 + if t > 0: + result.append(tens[t]) + + # یکان + o = remainder % 10 + if o > 0: + result.append(ones[o]) + + return " و ".join(result) + + # تقسیم عدد به گروههای سه رقمی + groups = [] + scale_index = 0 + + while number > 0: + group = number % 1000 + if group != 0: + group_text = convert_group(group) + if scale_index > 0: + group_text += " " + scale[scale_index] + groups.append(group_text) + + number //= 1000 + scale_index += 1 + + # معکوس کردن و ترکیب گروهها + groups.reverse() + result = " و ".join(groups) + + return result + + except Exception: + return "" + + +def amount_to_persian_words(amount): + """ + تبدیل مبلغ به حروف فارسی با واحد ریال + مثال: 12345 -> دوازده هزار و سیصد و چهل و پنج ریال + """ + try: + words = number_to_persian_words(amount) + if words: + return words + " ریال" + return "" + except Exception: + return "" \ No newline at end of file diff --git a/accounts/templates/accounts/login.html b/accounts/templates/accounts/login.html index e43800d..f66c7b5 100644 --- a/accounts/templates/accounts/login.html +++ b/accounts/templates/accounts/login.html @@ -64,7 +64,7 @@ layout-wide customizer-hide - سامانه شفافیت + کنتور پلاس diff --git a/certificates/admin.py b/certificates/admin.py index de9ba72..f1eff8a 100644 --- a/certificates/admin.py +++ b/certificates/admin.py @@ -12,9 +12,7 @@ class CertificateTemplateAdmin(admin.ModelAdmin): @admin.register(CertificateInstance) class CertificateInstanceAdmin(admin.ModelAdmin): - list_display = ('process_instance', 'rendered_title', 'issued_at', 'approved') + list_display = ('process_instance', 'rendered_title', 'hologram_code', 'issued_at', 'approved') list_filter = ('approved', 'issued_at') - search_fields = ('process_instance__code', 'rendered_title') + search_fields = ('process_instance__code', 'rendered_title', 'hologram_code') autocomplete_fields = ('process_instance', 'template') - - diff --git a/certificates/migrations/0003_alter_certificateinstance_hologram_code.py b/certificates/migrations/0003_alter_certificateinstance_hologram_code.py new file mode 100644 index 0000000..00fb9cd --- /dev/null +++ b/certificates/migrations/0003_alter_certificateinstance_hologram_code.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.4 on 2025-10-09 08:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('certificates', '0002_certificateinstance_hologram_code'), + ] + + operations = [ + migrations.AlterField( + model_name='certificateinstance', + name='hologram_code', + field=models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='کد یکتا هولوگرام'), + ), + ] diff --git a/certificates/models.py b/certificates/models.py index a7afe72..c374035 100644 --- a/certificates/models.py +++ b/certificates/models.py @@ -28,7 +28,7 @@ class CertificateInstance(BaseModel): issued_at = models.DateField(auto_now_add=True, verbose_name='تاریخ صدور') approved = models.BooleanField(default=False, verbose_name='تایید شده') approved_at = models.DateTimeField(null=True, blank=True, verbose_name='تاریخ تایید') - hologram_code = models.CharField(max_length=50, null=True, blank=True, verbose_name='کد یکتا هولوگرام') + hologram_code = models.CharField(max_length=50, null=True, blank=True, verbose_name='کد یکتا هولوگرام', unique=True) class Meta: verbose_name = 'گواهی' diff --git a/certificates/templates/certificates/step.html b/certificates/templates/certificates/step.html index 2f7e089..f8249cb 100644 --- a/certificates/templates/certificates/step.html +++ b/certificates/templates/certificates/step.html @@ -38,9 +38,11 @@
+ متأسفانه شما دسترسی لازم برای مشاهده این صفحه را ندارید.
+
تخفیف:
{% endif %}مالیات بر ارزش افزوده:
-مبلغ نهایی (شامل مالیات):
+مبلغ نهایی (شامل مالیات):
+مبلغ نهایی به حروف:
{{ quote.total_amount|floatformat:0|intcomma:False }} ریال
@@ -222,7 +230,8 @@{{ quote.discount_amount|floatformat:0|intcomma:False }} ریال
{% endif %}{{ quote.get_vat_amount|floatformat:0|intcomma:False }} ریال
-{{ quote.final_amount|floatformat:0|intcomma:False }} ریال
+{{ quote.final_amount|floatformat:0|intcomma:False }} ریال
+{{ quote.final_amount|amount_to_words }}