78 lines
3.7 KiB
Python
78 lines
3.7 KiB
Python
"""Reuse the contact directory's scoped history; never render all customer choices."""
|
|
from uuid import UUID
|
|
from django.db.models import Prefetch, Q
|
|
from django.http import Http404
|
|
from django.urls import reverse
|
|
from apps.accounts.models import normalize_mobile
|
|
from apps.core.persian_text import normalize_persian_text
|
|
from apps.tickets.selectors import staff_ticket_rows
|
|
from .validators import digits
|
|
|
|
|
|
def customer_rows(user, search=''):
|
|
# The existing directory projection counts only tickets visible to this staff user.
|
|
from apps.tickets.views import _customer_rows
|
|
rows = _customer_rows(user=user).filter(is_active=True)
|
|
if search:
|
|
terms_query = Q()
|
|
for term in search.split():
|
|
mobile = term
|
|
try:
|
|
mobile = normalize_mobile(term)
|
|
except ValueError:
|
|
if term.isascii() and term.isdecimal() and term.startswith('0'):
|
|
mobile = term[1:]
|
|
terms_query &= (Q(mobile__icontains=mobile) | Q(username__icontains=term) |
|
|
Q(first_name__icontains=term) | Q(last_name__icontains=term) |
|
|
Q(customer_profile__first_name__icontains=term) |
|
|
Q(customer_profile__last_name__icontains=term) |
|
|
Q(customer_profile__organization_name__icontains=term))
|
|
history = staff_ticket_rows(user).filter(
|
|
Q(ticket_number__icontains=search) | Q(subject__icontains=search) |
|
|
Q(subject__icontains=normalize_persian_text(search)))
|
|
rows = rows.filter(terms_query | Q(customer_tickets__pk__in=history.values('pk'))).distinct()
|
|
return rows.prefetch_related(Prefetch('customer_tickets',
|
|
queryset=staff_ticket_rows(user).order_by('-created_at', '-pk')[:3],
|
|
to_attr='payment_recent_tickets'))
|
|
|
|
|
|
def customer_data(customer):
|
|
profile = getattr(customer, 'customer_profile', None)
|
|
name = ' '.join(filter(None, [getattr(profile, 'first_name', ''), getattr(profile, 'last_name', '')]))
|
|
return {'value': str(customer.pk), 'id': str(customer.public_id),
|
|
'name': name or customer.get_full_name() or 'نام ثبت نشده',
|
|
'mobile': customer.local_mobile, 'organization': getattr(profile, 'organization_name', ''),
|
|
'location': '، '.join(filter(None, [getattr(profile, 'city', ''), getattr(profile, 'province', '')])),
|
|
'ticket_count': customer.ticket_count, 'active_count': customer.active_count,
|
|
'history': [{'number': ticket.ticket_number, 'subject': ticket.subject,
|
|
'status': ticket.get_status_display(), 'url': reverse('staff_tickets:detail', args=[ticket.public_id])}
|
|
for ticket in customer.payment_recent_tickets]}
|
|
|
|
|
|
def initial_customer(request):
|
|
public_id = request.GET.get('customer', '')
|
|
if not public_id or request.method != 'GET':
|
|
return {}
|
|
try:
|
|
public_id = UUID(public_id)
|
|
except (ValueError, TypeError, AttributeError):
|
|
raise Http404('مشتری معتبر نیست.')
|
|
customer = customer_rows(request.user).filter(public_id=public_id).first()
|
|
if customer is None:
|
|
raise Http404('مشتری فعال پیدا نشد.')
|
|
return {'customer': customer.pk}
|
|
|
|
|
|
def picker_context(request, form):
|
|
value = str(form['customer'].value() or '')
|
|
selected = customer_rows(request.user).filter(pk=value).first() if value.isascii() and value.isdecimal() else None
|
|
return {'customer_selection': customer_data(selected) if selected else None}
|
|
|
|
|
|
def search_results(user, query):
|
|
query = digits(query).translate(str.maketrans('يك', 'یک'))[:100]
|
|
if len(query) < 2:
|
|
return {'results': [], 'has_more': False}
|
|
rows = list(customer_rows(user, query)[:21])
|
|
return {'results': [customer_data(customer) for customer in rows[:20]], 'has_more': len(rows) > 20}
|