2026-05-20 10:50:30 +00:00

129 lines
3.7 KiB
Python

from decimal import Decimal, InvalidOperation
import re
from django.utils import timezone
def phone_has_valid_digits(phone):
digits = re.sub(r'\D+', '', (phone or '').strip())
return 7 <= len(digits) <= 15
def first_address_line(address):
trimmed = (address or '').strip()
if not trimmed:
return ''
return trimmed.splitlines()[0].strip()
def derive_location_label(location_label='', address=''):
label = (location_label or '').strip()
if label:
return label[:255]
return first_address_line(address)[:255]
def parse_decimal_value(raw_value, *, field_label, minimum=None, maximum=None):
value = (raw_value or '').strip()
if not value:
return None
try:
parsed = Decimal(value)
except (InvalidOperation, TypeError):
raise ValueError(f'Invalid {field_label}.')
if minimum is not None and parsed < minimum:
raise ValueError(f'{field_label.capitalize()} must be at least {minimum}.')
if maximum is not None and parsed > maximum:
raise ValueError(f'{field_label.capitalize()} must be no more than {maximum}.')
return parsed
def stringify_decimal(value):
if value in {None, ''}:
return ''
return str(value)
def build_delivery_payload(
*,
full_name='',
phone='',
address='',
location_label='',
delivery_notes='',
latitude=None,
longitude=None,
location_accuracy_m=None,
save_as_default=True,
**extra,
):
payload = {
'full_name': (full_name or '').strip(),
'phone': (phone or '').strip(),
'address': (address or '').strip(),
'location_label': derive_location_label(location_label, address),
'delivery_notes': (delivery_notes or '').strip(),
'latitude': stringify_decimal(latitude),
'longitude': stringify_decimal(longitude),
'location_accuracy_m': stringify_decimal(location_accuracy_m),
'save_as_default': bool(save_as_default),
}
payload.update(extra)
return payload
def profile_delivery_changes(*, phone, address, location_label='', latitude=None, longitude=None, location_accuracy_m=None):
return {
'phone': (phone or '').strip(),
'default_address': (address or '').strip(),
'location_label': derive_location_label(location_label, address),
'latitude': latitude,
'longitude': longitude,
'location_accuracy_m': location_accuracy_m,
'location_updated_at': timezone.now() if latitude is not None and longitude is not None else None,
}
def apply_profile_delivery_fields(profile, **kwargs):
changes = profile_delivery_changes(**kwargs)
for field, value in changes.items():
setattr(profile, field, value)
return profile
def save_profile_delivery_defaults(profile, **kwargs):
if profile is None:
return []
changes = profile_delivery_changes(**kwargs)
update_fields = []
for field, value in changes.items():
if getattr(profile, field) != value:
setattr(profile, field, value)
update_fields.append(field)
if update_fields:
profile.save(update_fields=update_fields)
return update_fields
def delivery_payload_from_profile(profile, *, full_name='', **extra):
if profile is None:
return build_delivery_payload(full_name=full_name, **extra)
return build_delivery_payload(
full_name=full_name,
phone=profile.phone,
address=profile.formatted_delivery_address,
location_label=profile.short_location,
latitude=profile.latitude,
longitude=profile.longitude,
location_accuracy_m=profile.location_accuracy_m,
save_as_default=True,
**extra,
)