@@ -436,8 +583,96 @@
// Customer functions
function viewCustomer(id) {
- // Implement view functionality
- console.log('View customer:', id);
+ const modalEl = document.getElementById('customerDetailsModal');
+ const modal = new bootstrap.Modal(modalEl);
+ // reset content
+ $('#customer-details-content').hide();
+ $('#customer-details-loading').show();
+ $('#cd-wells-body').html('
در حال بارگذاری... |
');
+ $('#cd-requests-body').html('
در حال بارگذاری... |
');
+ $('#cd-wells-count').text('0');
+ $('#cd-requests-count').text('0');
+ modal.show();
+
+ // Fetch customer details
+ $.get('{% url "accounts:get_customer_details" 0 %}'.replace('0', id))
+ .done(function(resp){
+ if (!resp.success) { showToast('خطا در دریافت جزئیات مشترک', 'danger'); return; }
+ const c = resp.customer;
+ $('#customerDetailsModalLabel').text('جزئیات مشترک ' + (c.user.full_name || c.user.username));
+ $('#cd-username').text(c.user.username || '-');
+ $('#cd-fullname').text(c.user.full_name || '-');
+ $('#cd-national-code').text(c.national_code || '-');
+ $('#cd-phone1').text(c.phone_number_1 || '-');
+ $('#cd-phone2').text(c.phone_number_2 || '-');
+ $('#cd-email').text(c.user.email || '-');
+ $('#cd-card').text(c.card_number || '-');
+ $('#cd-account').text(c.account_number || '-');
+ $('#cd-bank').text(c.bank_name || '-');
+ $('#cd-address').text(c.address || '-');
+ $('#cd-joined').text(c.user.date_joined || '-');
+
+ // Status badge
+ if (c.is_completed) {
+ $('#cd-status').removeClass().addClass('badge bg-success').text('تکمیل شده');
+ } else {
+ $('#cd-status').removeClass().addClass('badge bg-warning').text('ناقص');
+ }
+
+ $('#cd-wells-count').text(resp.total_wells || '0');
+ $('#cd-requests-count').text(resp.total_requests || '0');
+ $('#customer-details-loading').hide();
+ $('#customer-details-content').show();
+ })
+ .fail(function(){ showToast('خطا در ارتباط با سرور', 'danger'); $('#customer-details-loading').hide(); });
+
+ // Fetch wells
+ $.get('{% url "accounts:get_customer_wells" 0 %}'.replace('0', id))
+ .done(function(resp){
+ if (!resp.success) { $('#cd-wells-body').html('
خطا در بارگذاری چاهها |
'); return; }
+ const rows = (resp.wells || []).map(function(w){
+ return '
'+
+ ''+ (w.water_subscription_number || '-') +' | '+
+ ''+ (w.electricity_subscription_number || '-') +' | '+
+ ''+ (w.water_meter_serial_number || '-') +' | '+
+ ''+ (w.water_meter_manufacturer || '-') +' | '+
+ ''+ (w.created || '-') +' | '+
+ '
';
+ });
+ if (!rows.length) {
+ $('#cd-wells-body').html('
رکوردی یافت نشد |
');
+ } else {
+ $('#cd-wells-body').html(rows.join(''));
+ }
+ })
+ .fail(function(){ $('#cd-wells-body').html('
خطا در بارگذاری چاهها |
'); });
+
+ // Fetch requests
+ $.get('{% url "accounts:get_customer_requests" 0 %}'.replace('0', id))
+ .done(function(resp){
+ if (!resp.success) { $('#cd-requests-body').html('
خطا در بارگذاری درخواستها |
'); return; }
+ const rows = (resp.requests || []).map(function(r){
+ const status = r.status_display || r.status;
+ const step = r.current_step || '-';
+ const href = r.url || '#';
+ const well = r.well_subscription || '-';
+ return '
'+
+ ''+ (r.code || '-') +' | '+
+ ''+ (r.process || '-') +' | '+
+ ''+ well +' | '+
+ ''+ step +' | '+
+ ''+ status +' | '+
+ ''+ (r.created || '-') +' | '+
+ 'جزئیات | '+
+ '
';
+ });
+ if (!rows.length) {
+ $('#cd-requests-body').html('
رکوردی یافت نشد |
');
+ } else {
+ $('#cd-requests-body').html(rows.join(''));
+ }
+ })
+ .fail(function(){ $('#cd-requests-body').html('
خطا در بارگذاری درخواستها |
'); });
}
function editCustomer(id) {
diff --git a/accounts/urls.py b/accounts/urls.py
index 7c79207..efe27ad 100644
--- a/accounts/urls.py
+++ b/accounts/urls.py
@@ -1,6 +1,9 @@
from django.urls import path
-from accounts.views import login_view, dashboard, customer_list, add_customer_ajax, edit_customer_ajax, get_customer_data, logout_view
+from accounts.views import (
+ login_view, dashboard, customer_list, add_customer_ajax, edit_customer_ajax,
+ get_customer_data, get_customer_details, get_customer_wells, get_customer_requests, logout_view
+)
app_name = "accounts"
urlpatterns = [
@@ -11,4 +14,7 @@ urlpatterns = [
path('customers/add/', add_customer_ajax, name='add_customer_ajax'),
path('customers/
/data/', get_customer_data, name='get_customer_data'),
path('customers//edit/', edit_customer_ajax, name='edit_customer_ajax'),
+ path('customers//details/', get_customer_details, name='get_customer_details'),
+ path('customers//wells/', get_customer_wells, name='get_customer_wells'),
+ path('customers//requests/', get_customer_requests, name='get_customer_requests'),
]
\ No newline at end of file
diff --git a/accounts/views.py b/accounts/views.py
index c5bec75..fea6375 100644
--- a/accounts/views.py
+++ b/accounts/views.py
@@ -6,6 +6,7 @@ from django.views.decorators.http import require_POST, require_GET
from django.views.decorators.csrf import csrf_exempt
from django import forms
from django.contrib.auth.decorators import login_required
+from django.urls import reverse
from accounts.models import Profile
from accounts.forms import CustomerForm
from processes.utils import scope_customers_queryset
@@ -174,6 +175,128 @@ def get_customer_data(request, customer_id):
})
+@require_GET
+@login_required
+@allowed_roles([UserRoles.ADMIN, UserRoles.BROKER, UserRoles.MANAGER, UserRoles.ACCOUNTANT])
+def get_customer_details(request, customer_id):
+ """جزئیات کامل مشترک برای نمایش در مدال"""
+ customer = get_object_or_404(
+ Profile.objects.select_related('user', 'affairs', 'county', 'broker'),
+ id=customer_id
+ )
+
+ data = {
+ 'id': customer.id,
+ 'user': {
+ 'username': customer.user.username,
+ 'first_name': customer.user.first_name or '',
+ 'last_name': customer.user.last_name or '',
+ 'full_name': customer.user.get_full_name() or customer.user.username,
+ 'email': customer.user.email or '',
+ 'date_joined': customer.jcreated_date() if customer.user.date_joined else '',
+ },
+ 'national_code': customer.national_code or '',
+ 'phone_number_1': customer.phone_number_1 or '',
+ 'phone_number_2': customer.phone_number_2 or '',
+ 'card_number': customer.card_number or '',
+ 'account_number': customer.account_number or '',
+ 'bank_name': customer.get_bank_name_display() or '',
+ 'address': customer.address or '',
+ 'pic_url': customer.pic.url if customer.pic else '',
+ 'affairs': str(customer.affairs) if customer.affairs else '',
+ 'county': str(customer.county) if customer.county else '',
+ 'broker': str(customer.broker) if customer.broker else '',
+ 'is_completed': customer.is_completed,
+ }
+
+ # تعداد چاهها و درخواستها برای نمایش سریع
+ try:
+ from wells.models import Well
+ from processes.models import ProcessInstance
+ total_wells = Well.objects.filter(representative=customer.user, is_deleted=False).count()
+ total_requests = ProcessInstance.objects.filter(representative=customer.user, is_deleted=False).count()
+ except Exception:
+ total_wells = 0
+ total_requests = 0
+
+ return JsonResponse({
+ 'success': True,
+ 'customer': data,
+ 'total_wells': total_wells,
+ 'total_requests': total_requests
+ })
+
+
+@require_GET
+@login_required
+@allowed_roles([UserRoles.ADMIN, UserRoles.BROKER, UserRoles.MANAGER, UserRoles.ACCOUNTANT])
+def get_customer_wells(request, customer_id):
+ """چاههای مرتبط با یک مشترک"""
+ customer = get_object_or_404(Profile, id=customer_id)
+
+ try:
+ from wells.models import Well
+ qs = Well.objects.select_related(
+ 'water_meter_manufacturer', 'affairs', 'county', 'broker'
+ ).filter(representative=customer.user, is_deleted=False).order_by('-created')
+
+ items = []
+ for well in qs[:100]: # محدودسازی برای عملکرد
+ items.append({
+ 'id': well.id,
+ 'water_subscription_number': well.water_subscription_number,
+ 'electricity_subscription_number': well.electricity_subscription_number or '',
+ 'water_meter_serial_number': well.water_meter_serial_number or '',
+ 'water_meter_manufacturer': str(well.water_meter_manufacturer) if well.water_meter_manufacturer else '',
+ 'well_power': well.well_power or '',
+ 'affairs': str(well.affairs) if well.affairs else '',
+ 'county': str(well.county) if well.county else '',
+ 'broker': str(well.broker) if well.broker else '',
+ 'created': well.jcreated_date() if hasattr(well, 'created') and well.created else '',
+ })
+ except Exception:
+ items = []
+
+ return JsonResponse({'success': True, 'wells': items})
+
+
+@require_GET
+@login_required
+@allowed_roles([UserRoles.ADMIN, UserRoles.BROKER, UserRoles.MANAGER, UserRoles.ACCOUNTANT])
+def get_customer_requests(request, customer_id):
+ """درخواستهای مرتبط با یک مشترک"""
+ customer = get_object_or_404(Profile, id=customer_id)
+
+ try:
+ from processes.models import ProcessInstance
+ qs = ProcessInstance.objects.select_related(
+ 'process', 'current_step', 'requester', 'well'
+ ).filter(representative=customer.user, is_deleted=False).order_by('-created')
+
+ items = []
+ for inst in qs[:100]: # محدودسازی برای عملکرد
+ try:
+ url = reverse('processes:instance_summary', args=[inst.id]) if inst.status == 'completed' else reverse('processes:instance_steps', args=[inst.id])
+ except Exception:
+ url = ''
+ items.append({
+ 'id': inst.id,
+ 'code': inst.code,
+ 'process': inst.process.name if inst.process else '',
+ 'status': inst.status,
+ 'status_display': inst.get_status_display(),
+ 'current_step': inst.current_step.name if inst.current_step else '',
+ 'requester': inst.requester.get_full_name() if inst.requester else '',
+ 'well_subscription': inst.well.water_subscription_number if inst.well else '',
+ 'created': inst.jcreated_date() if hasattr(inst, 'created') and inst.created else '',
+ 'url': url,
+ })
+ except Exception:
+ items = []
+
+ return JsonResponse({'success': True, 'requests': items})
+
+
@login_required
def logout_view(request):
"""Log out current user and redirect to login page."""
diff --git a/wells/templates/wells/well_list.html b/wells/templates/wells/well_list.html
index 2215165..1eb585e 100644
--- a/wells/templates/wells/well_list.html
+++ b/wells/templates/wells/well_list.html
@@ -338,6 +338,134 @@