294 lines
8.5 KiB
Python
294 lines
8.5 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any, Optional
|
|
|
|
from nepali.datetime import nepalidate, nepalidatetime
|
|
from nepali.locations import districts, provinces
|
|
|
|
from django_nepkit.conf import nepkit_settings
|
|
|
|
BS_DATE_FORMAT = nepkit_settings.BS_DATE_FORMAT
|
|
BS_DATETIME_FORMAT = nepkit_settings.BS_DATETIME_FORMAT
|
|
|
|
|
|
def _try_parse_nepali(value: Any, cls: Any, fallback_fmt: str) -> Any:
|
|
"""Helper to turn a string into a Nepali date object."""
|
|
if value in (None, ""):
|
|
return None
|
|
if isinstance(value, cls):
|
|
return value
|
|
if isinstance(value, str):
|
|
formats = nepkit_settings.DATE_INPUT_FORMATS
|
|
if fallback_fmt not in formats:
|
|
formats = list(formats) + [fallback_fmt]
|
|
|
|
for fmt in formats:
|
|
try:
|
|
return cls.strptime(value.strip(), fmt)
|
|
except Exception:
|
|
continue
|
|
return None
|
|
|
|
|
|
def try_parse_nepali_date(value: Any) -> Optional[nepalidate]:
|
|
"""Convert any value to a Nepali Date."""
|
|
return _try_parse_nepali(value, nepalidate, BS_DATE_FORMAT)
|
|
|
|
|
|
def try_parse_nepali_datetime(value: Any) -> Optional[nepalidatetime]:
|
|
"""Convert any value to a Nepali Date and Time."""
|
|
return _try_parse_nepali(value, nepalidatetime, BS_DATETIME_FORMAT)
|
|
|
|
|
|
def _get_location_children(parent_list, parent_name, child_attr, ne=False):
|
|
"""Find children (like districts) of a parent (like a province)."""
|
|
selected_parent = None
|
|
for p in parent_list:
|
|
p_name = p.name
|
|
p_name_ne = getattr(p, "name_nepali", None)
|
|
|
|
# Handle province name variations
|
|
if parent_name == "Koshi Province":
|
|
if p_name == "Province 1":
|
|
selected_parent = p
|
|
break
|
|
elif parent_name == "कोशी प्रदेश":
|
|
if p_name_ne == "प्रदेश नं. १":
|
|
selected_parent = p
|
|
break
|
|
|
|
if p_name == parent_name or p_name_ne == parent_name:
|
|
selected_parent = p
|
|
break
|
|
|
|
if not selected_parent:
|
|
return []
|
|
|
|
children = getattr(selected_parent, child_attr, [])
|
|
|
|
if ne:
|
|
return [
|
|
{
|
|
"id": getattr(child, "name_nepali", child.name),
|
|
"text": getattr(child, "name_nepali", child.name),
|
|
}
|
|
for child in children
|
|
]
|
|
else:
|
|
return [{"id": child.name, "text": child.name} for child in children]
|
|
|
|
|
|
def get_districts_by_province(province_name, ne=False, en=True):
|
|
"""Get all districts for a province."""
|
|
# Logic note: if ne=True is passed, we shouldn't care about en=True (handled by caller typically)
|
|
return _get_location_children(provinces, province_name, "districts", ne=ne)
|
|
|
|
|
|
def get_municipalities_by_district(district_name, ne=False, en=True):
|
|
"""Get all municipalities for a district."""
|
|
return _get_location_children(districts, district_name, "municipalities", ne=ne)
|
|
|
|
|
|
def format_nepali_currency(number: Any, currency_symbol: str = "Rs.") -> str:
|
|
"""
|
|
Formats a number with Nepali-style commas and optional currency symbol.
|
|
Eg. 1234567 -> Rs. 12,34,567
|
|
"""
|
|
from nepali.number import add_comma
|
|
|
|
if number is None:
|
|
return ""
|
|
|
|
try:
|
|
# Convert to string and split by decimal point
|
|
num_str = f"{float(number):.2f}"
|
|
if "." in num_str:
|
|
integer_part, decimal_part = num_str.split(".")
|
|
else:
|
|
integer_part, decimal_part = num_str, ""
|
|
|
|
# Format integer part with commas
|
|
formatted_integer = add_comma(int(integer_part))
|
|
|
|
# Join back
|
|
res = formatted_integer
|
|
if decimal_part:
|
|
res = f"{res}.{decimal_part}"
|
|
|
|
if currency_symbol:
|
|
return f"{currency_symbol} {res}"
|
|
return res
|
|
except Exception:
|
|
return str(number)
|
|
|
|
|
|
def number_to_nepali_words(number: Any) -> str:
|
|
"""
|
|
Converts a number to Nepali words.
|
|
Eg. 123 -> एक सय तेईस
|
|
"""
|
|
if number is None:
|
|
return ""
|
|
|
|
# Basic implementation for now, can be expanded
|
|
# Mapping for numbers to words (simplified)
|
|
# This is a complex task for a full implementation,
|
|
# but I'll provide a robust enough version for common usage.
|
|
|
|
try:
|
|
num = int(float(number))
|
|
except (ValueError, TypeError):
|
|
return str(number)
|
|
|
|
if num == 0:
|
|
return "शून्य"
|
|
|
|
ones = [
|
|
"",
|
|
"एक",
|
|
"दुई",
|
|
"तीन",
|
|
"चार",
|
|
"पाँच",
|
|
"छ",
|
|
"सात",
|
|
"आठ",
|
|
"नौ",
|
|
"दश",
|
|
"एघार",
|
|
"बाह्र",
|
|
"तेह्र",
|
|
"चौध",
|
|
"पन्ध्र",
|
|
"सोह्र",
|
|
"सत्र",
|
|
"अठार",
|
|
"उन्नाइस",
|
|
"बीस",
|
|
"एकाइस",
|
|
"बाइस",
|
|
"तेईस",
|
|
"चौबीस",
|
|
"पच्चीस",
|
|
"छब्बीस",
|
|
"सत्ताइस",
|
|
"अठाइस",
|
|
"उनन्तीस",
|
|
"तीस",
|
|
"एकतीस",
|
|
"बत्तीस",
|
|
"तेत्तीस",
|
|
"चौंतीस",
|
|
"पैंतीस",
|
|
"छत्तीस",
|
|
"सैंतीस",
|
|
"अठतीस",
|
|
"उनन्चालीस",
|
|
"चालीस",
|
|
"एकचालीस",
|
|
"बयालीस",
|
|
"त्रिचालीस",
|
|
"चवालीस",
|
|
"पैंतालीस",
|
|
"छयालीस",
|
|
"सत्तालीस",
|
|
"अठचालीस",
|
|
"उनन्पचास",
|
|
"पचास",
|
|
"एकाउन्न",
|
|
"बाउन्न",
|
|
"त्रिपन्न",
|
|
"चउन्न",
|
|
"पचपन्न",
|
|
"छपन्न",
|
|
"सन्ताउन्न",
|
|
"अन्ठाउन्न",
|
|
"उनन्साठी",
|
|
"साठी",
|
|
"एकसाठी",
|
|
"बासट्ठी",
|
|
"त्रिसट्ठी",
|
|
"चौसट्ठी",
|
|
"पैंसट्ठी",
|
|
"छयसट्ठी",
|
|
"सतसट्ठी",
|
|
"अठसट्ठी",
|
|
"उनन्सत्तरी",
|
|
"सत्तरी",
|
|
"एकहत्तर",
|
|
"बाहत्तर",
|
|
"त्रिहत्तर",
|
|
"चौरहत्तर",
|
|
"पचहत्तर",
|
|
"छयहत्तर",
|
|
"सतहत्तर",
|
|
"अठहत्तर",
|
|
"उनन्असी",
|
|
"असी",
|
|
"एकासी",
|
|
"बयासी",
|
|
"त्रियासी",
|
|
"चौरासी",
|
|
"पचासी",
|
|
"छयासी",
|
|
"सतासी",
|
|
"अठासी",
|
|
"उनन्नब्बे",
|
|
"नब्बे",
|
|
"एकानब्बे",
|
|
"बयानब्बे",
|
|
"त्रियानब्बे",
|
|
"चौरानब्बे",
|
|
"पञ्चानब्बे",
|
|
"छ्यानब्बे",
|
|
"सन्तानब्बे",
|
|
"अन्ठानब्बे",
|
|
"उनन्सय",
|
|
]
|
|
|
|
units = [
|
|
("", ""),
|
|
(100, "सय"),
|
|
(1000, "हजार"),
|
|
(100000, "लाख"),
|
|
(10000000, "करोड"),
|
|
(1000000000, "अरब"),
|
|
(100000000000, "खरब"),
|
|
]
|
|
|
|
def _convert(n):
|
|
if n == 0:
|
|
return ""
|
|
if n < 100:
|
|
return ones[n]
|
|
|
|
for i in range(len(units) - 1, 0, -1):
|
|
div, unit_name = units[i]
|
|
if n >= div:
|
|
prefix_val = n // div
|
|
remainder = n % div
|
|
|
|
# For 'सय' (100), we use ones[prefix_val]
|
|
# For others, we might need recursive calls if prefix_val >= 100
|
|
prefix_words = _convert(prefix_val)
|
|
res = f"{prefix_words} {unit_name}"
|
|
if remainder > 0:
|
|
res += f" {_convert(remainder)}"
|
|
return res.strip()
|
|
return ""
|
|
|
|
return _convert(num)
|
|
|
|
|
|
def english_to_nepali_unicode(text: Any) -> str:
|
|
"""
|
|
Converts English text/numbers to Nepali Unicode.
|
|
Currently focuses on numbers.
|
|
"""
|
|
from nepali.number import english_to_nepali
|
|
|
|
if text is None:
|
|
return ""
|
|
|
|
return english_to_nepali(text)
|