883 lines
		
	
	
	
		
			38 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			883 lines
		
	
	
	
		
			38 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
{% extends '_base.html' %}
 | 
						|
{% load static %}
 | 
						|
 | 
						|
{% block sidebar %}
 | 
						|
    {% include 'sidebars/admin.html' %}
 | 
						|
{% endblock sidebar %}
 | 
						|
 | 
						|
{% block navbar %}
 | 
						|
    {% include 'navbars/admin.html' %}
 | 
						|
{% endblock navbar %}
 | 
						|
 | 
						|
 | 
						|
{% block title %}درخواستها{% endblock %}
 | 
						|
 | 
						|
{% block style %}
 | 
						|
<!-- DataTables CSS -->
 | 
						|
<link rel="stylesheet" href="{% static 'assets/vendor/libs/datatables-bs5/datatables.bootstrap5.css' %}">
 | 
						|
<link rel="stylesheet" href="{% static 'assets/vendor/libs/datatables-responsive-bs5/responsive.bootstrap5.css' %}">
 | 
						|
<link rel="stylesheet" href="{% static 'assets/vendor/libs/datatables-buttons-bs5/buttons.bootstrap5.css' %}">
 | 
						|
<!-- Persian Date Picker CSS -->
 | 
						|
<link rel="stylesheet" href="https://unpkg.com/persian-datepicker@latest/dist/css/persian-datepicker.min.css">
 | 
						|
 | 
						|
{% endblock style %}
 | 
						|
 | 
						|
 | 
						|
{% block content %}
 | 
						|
{% include '_toasts.html' %}
 | 
						|
 | 
						|
<div class="container-xxl flex-grow-1 container-p-y">
 | 
						|
 | 
						|
  <div class="row py-3 mb-4 card-header flex-column flex-md-row pb-0">
 | 
						|
    <div class="d-md-flex justify-content-between align-items-center dt-layout-start col-md-auto me-auto mt-0">
 | 
						|
      <h5 class="card-title mb-0 text-md-start text-center fw-bold">لیست درخواستها</h5>
 | 
						|
    </div>
 | 
						|
    <div class="d-md-flex justify-content-between align-items-center dt-layout-end col-md-auto ms-auto mt-0">
 | 
						|
      <div class="dt-buttons btn-group flex-wrap mb-0">
 | 
						|
        <div class="btn-group">
 | 
						|
          <button class="btn buttons-collection btn-label-primary dropdown-toggle me-4 d-none" type="button">
 | 
						|
            <span>
 | 
						|
              <span class="d-flex align-items-center gap-2">
 | 
						|
                <i class="icon-base bx bx-export me-sm-1"></i>
 | 
						|
                <span class="d-none d-sm-inline-block">خروجی</span>
 | 
						|
              </span>
 | 
						|
            </span>
 | 
						|
          </button>
 | 
						|
          <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#requestModal">
 | 
						|
            <i class="bx bx-plus me-1"></i>
 | 
						|
            درخواست جدید
 | 
						|
          </button>
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
  </div>
 | 
						|
 | 
						|
  <!-- Summary Cards -->
 | 
						|
  <div class="row g-4 mb-4">
 | 
						|
    <div class="col-sm-6 col-xl-3">
 | 
						|
      <div class="card">
 | 
						|
        <div class="card-body">
 | 
						|
          <div class="d-flex align-items-start justify-content-between">
 | 
						|
            <div class="content-left">
 | 
						|
              <span>کل درخواستها</span>
 | 
						|
              <div class="d-flex align-items-end mt-2">
 | 
						|
                <h4 class="mb-0 me-2">{{ total_count }}</h4>
 | 
						|
              </div>
 | 
						|
            </div>
 | 
						|
            <div class="avatar">
 | 
						|
              <span class="avatar-initial rounded bg-label-primary">
 | 
						|
                <i class="bx bx-list-ul bx-sm"></i>
 | 
						|
              </span>
 | 
						|
            </div>
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
    <div class="col-sm-6 col-xl-3">
 | 
						|
      <div class="card">
 | 
						|
        <div class="card-body">
 | 
						|
          <div class="d-flex align-items-start justify-content-between">
 | 
						|
            <div class="content-left">
 | 
						|
              <span>تکمیلشده</span>
 | 
						|
              <div class="d-flex align-items-end mt-2">
 | 
						|
                <h4 class="mb-0 me-2">{{ completed_count }}</h4>
 | 
						|
              </div>
 | 
						|
            </div>
 | 
						|
            <div class="avatar">
 | 
						|
              <span class="avatar-initial rounded bg-label-success">
 | 
						|
                <i class="bx bx-badge-check bx-sm"></i>
 | 
						|
              </span>
 | 
						|
            </div>
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
    <div class="col-sm-6 col-xl-3">
 | 
						|
      <div class="card">
 | 
						|
        <div class="card-body">
 | 
						|
          <div class="d-flex align-items-start justify-content-between">
 | 
						|
            <div class="content-left">
 | 
						|
              <span>در حال انجام</span>
 | 
						|
              <div class="d-flex align-items-end mt-2">
 | 
						|
                <h4 class="mb-0 me-2">{{ in_progress_count }}</h4>
 | 
						|
              </div>
 | 
						|
            </div>
 | 
						|
            <div class="avatar">
 | 
						|
              <span class="avatar-initial rounded bg-label-info">
 | 
						|
                <i class="bx bx-loader-circle bx-sm"></i>
 | 
						|
              </span>
 | 
						|
            </div>
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
    <div class="col-sm-6 col-xl-3">
 | 
						|
      <div class="card">
 | 
						|
        <div class="card-body">
 | 
						|
          <div class="d-flex align-items-start justify-content-between">
 | 
						|
            <div class="content-left">
 | 
						|
              <span>در انتظار</span>
 | 
						|
              <div class="d-flex align-items-end mt-2">
 | 
						|
                <h4 class="mb-0 me-2">{{ pending_count }}</h4>
 | 
						|
              </div>
 | 
						|
            </div>
 | 
						|
            <div class="avatar">
 | 
						|
              <span class="avatar-initial rounded bg-label-warning">
 | 
						|
                <i class="bx bx-time bx-sm"></i>
 | 
						|
              </span>
 | 
						|
            </div>
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
  </div>
 | 
						|
 | 
						|
  <div class="card">
 | 
						|
    <div class="card-datatable table-responsive">
 | 
						|
      <table id="requests-table" class="datatables-basic table border-top">
 | 
						|
        <thead>
 | 
						|
          <tr>
 | 
						|
            <th>شناسه</th>
 | 
						|
            <th>فرآیند</th>
 | 
						|
            <th>مرحله فعلی</th>
 | 
						|
            <th>شماره اشتراک آب</th>
 | 
						|
            <th>نماینده</th>
 | 
						|
            <th>استان</th>
 | 
						|
            <th>امور</th>
 | 
						|
            <th>پیشرفت</th>
 | 
						|
            <th>وضعیت</th>
 | 
						|
            <th>تاریخ ایجاد</th>
 | 
						|
            <th>عملیات</th>
 | 
						|
          </tr>
 | 
						|
        </thead>
 | 
						|
        <tbody>
 | 
						|
          {% for item in instances_with_progress %}
 | 
						|
          <tr>
 | 
						|
            <td>{{ item.instance.code }}</td>
 | 
						|
            <td>{{ item.instance.process.name }}</td>
 | 
						|
            <td class="text-primary">
 | 
						|
              {% if item.instance.status == 'completed' %}
 | 
						|
                <a href="{% url 'processes:instance_summary' item.instance.id %}" class="text-primary">{{ item.instance.current_step.name|default:"--" }}</a>
 | 
						|
              {% elif item.instance.current_step %}
 | 
						|
                <a href="{% url 'processes:instance_steps' item.instance.id %}" class="text-primary">{{ item.instance.current_step.name }}</a>
 | 
						|
              {% else %}
 | 
						|
                --
 | 
						|
              {% endif %}
 | 
						|
            </td>
 | 
						|
            <td>{{ item.instance.well.water_subscription_number }}</td>
 | 
						|
            <td>{% if item.instance.representative %}{{ item.instance.representative.get_full_name }}{% else %}-{% endif %}</td>
 | 
						|
            <td>{% if item.instance.well and item.instance.well.county %}{{ item.instance.well.county }}{% else %}-{% endif %}</td>
 | 
						|
            <td>{% if item.instance.well and item.instance.well.affairs %}{{ item.instance.well.affairs }}{% else %}-{% endif %}</td>
 | 
						|
            <td>
 | 
						|
              <div class="d-flex align-items-center">
 | 
						|
                <div class="progress me-2" style="width: 80px; height: 6px;">
 | 
						|
                  <div class="progress-bar {% if item.progress_percentage == 100 %}bg-success{% elif item.progress_percentage >= 70 %}bg-info{% elif item.progress_percentage >= 40 %}bg-warning{% else %}bg-secondary{% endif %}" role="progressbar" style="width: {{ item.progress_percentage }}%;" aria-valuenow="{{ item.progress_percentage }}" aria-valuemin="0" aria-valuemax="100">
 | 
						|
                  </div>
 | 
						|
                </div>
 | 
						|
                <small class="text-muted">{{ item.progress_percentage }}%</small>
 | 
						|
              </div>
 | 
						|
            </td>
 | 
						|
            <td>{{ item.instance.get_status_display_with_color|safe }}</td>
 | 
						|
            <td>{{ item.instance.jcreated }}</td>
 | 
						|
            <td>
 | 
						|
              <div class="d-inline-block">
 | 
						|
                <a href="javascript:;" class="btn btn-icon dropdown-toggle hide-arrow" data-bs-toggle="dropdown">
 | 
						|
                  <i class="icon-base bx bx-dots-vertical-rounded"></i>
 | 
						|
                </a>
 | 
						|
                <ul class="dropdown-menu dropdown-menu-end m-0">
 | 
						|
                  <li>
 | 
						|
                    {% if item.instance.status == 'completed' %}
 | 
						|
                      <a href="{% url 'processes:instance_summary' item.instance.id %}" class="dropdown-item">
 | 
						|
                        <i class="bx bx-show me-1"></i>مشاهده گزارش
 | 
						|
                      </a>
 | 
						|
                    {% else %}
 | 
						|
                      <a href="{% url 'processes:instance_steps' item.instance.id %}" class="dropdown-item">
 | 
						|
                        <i class="bx bx-show me-1"></i>مشاهده جزئیات
 | 
						|
                      </a>
 | 
						|
                    {% endif %}
 | 
						|
                  </li>
 | 
						|
                  <div class="dropdown-divider"></div>
 | 
						|
                  <li>
 | 
						|
                    <a href="#" class="dropdown-item text-danger" data-instance-id="{{ item.instance.id }}" data-instance-code="{{ item.instance.code }}" onclick="deleteRequest(this.getAttribute('data-instance-id'), this.getAttribute('data-instance-code'))">
 | 
						|
                      <i class="bx bx-trash me-1"></i>حذف
 | 
						|
                    </a>
 | 
						|
                  </li>
 | 
						|
                </ul>
 | 
						|
              </div>
 | 
						|
            </td>
 | 
						|
          </tr>
 | 
						|
          {% empty %}
 | 
						|
          <tr>
 | 
						|
            <td colspan="11" class="text-center text-muted">موردی ثبت نشده است</td>
 | 
						|
          </tr>
 | 
						|
          {% endfor %}
 | 
						|
        </tbody>
 | 
						|
      </table>
 | 
						|
    </div>
 | 
						|
  </div>
 | 
						|
 | 
						|
  <!-- Modal -->
 | 
						|
  <div class="modal fade" id="requestModal" tabindex="-1" aria-hidden="true">
 | 
						|
    <div class="modal-dialog modal-lg modal-dialog-centered">
 | 
						|
      <div class="modal-content">
 | 
						|
        <div class="modal-header">
 | 
						|
          <h5 class="modal-title">درخواست جدید</h5>
 | 
						|
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
 | 
						|
        </div>
 | 
						|
        <div class="modal-body">
 | 
						|
          <form id="requestForm">
 | 
						|
            {% csrf_token %}
 | 
						|
            <div class="row g-3">
 | 
						|
              <div class="col-sm-12">
 | 
						|
                <label class="form-label">فرآیند</label>
 | 
						|
                <select class="form-select" name="process" id="req_process" required>
 | 
						|
                  {% for process in processes %}
 | 
						|
                  <option value="{{ process.id }}">{{ process.name }}</option>
 | 
						|
                  {% endfor %}
 | 
						|
                </select>
 | 
						|
              </div>
 | 
						|
              <hr class="mt-3 border border-dashed">
 | 
						|
              <div class="col-sm-12">
 | 
						|
                <label class="form-label">شماره اشتراک آب</label>
 | 
						|
                <div class="input-group">
 | 
						|
                  <input type="text" class="form-control" id="req_water_sub" name="water_subscription_number" data-field="water_subscription_number" placeholder="مثال: 12345" required>
 | 
						|
                  <button class="btn btn-outline-secondary" type="button" id="btnLookupWell">
 | 
						|
                    بررسی/افزودن چاه
 | 
						|
                  </button>
 | 
						|
                </div>
 | 
						|
                <div class="form-text" id="wellStatus"></div>
 | 
						|
              </div>
 | 
						|
 | 
						|
 | 
						|
              <!-- Well form fields (from WellForm) -->
 | 
						|
              <div id="wellFormBlock" class="col-sm-12" style="display:none;">
 | 
						|
                <div class="row g-3">
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_electricity_subscription_number">{{ well_form.electricity_subscription_number.label }}</label>
 | 
						|
                    {{ well_form.electricity_subscription_number }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_water_meter_manufacturer">{{ well_form.water_meter_manufacturer.label }}</label>
 | 
						|
                    <div class="input-group">
 | 
						|
                      <select name="water_meter_manufacturer" class="form-select" id="id_water_meter_manufacturer">
 | 
						|
                        <option value="" selected="">انتخاب شرکت سازنده</option>
 | 
						|
                        {% for manufacturer in manufacturers %}
 | 
						|
                        <option value="{{ manufacturer.id }}">{{ manufacturer.name }}</option>
 | 
						|
                        {% endfor %}
 | 
						|
                      </select>
 | 
						|
                      <input type="text" class="form-control" id="id_new_manufacturer" name="new_manufacturer" placeholder="شرکت سازنده جدید" style="display:none;">
 | 
						|
                      <button class="btn btn-outline-primary" type="button" id="btnToggleManufacturer">
 | 
						|
                        <i class="bx bx-plus"></i>
 | 
						|
                      </button>
 | 
						|
                    </div>
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_water_meter_serial_number">{{ well_form.water_meter_serial_number.label }}</label>
 | 
						|
                    {{ well_form.water_meter_serial_number }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_water_meter_old_serial_number">{{ well_form.water_meter_old_serial_number.label }}</label>
 | 
						|
                    {{ well_form.water_meter_old_serial_number }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_utm_x">{{ well_form.utm_x.label }}</label>
 | 
						|
                    {{ well_form.utm_x }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_utm_y">{{ well_form.utm_y.label }}</label>
 | 
						|
                    {{ well_form.utm_y }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_utm_zone">{{ well_form.utm_zone.label }}</label>
 | 
						|
                    {{ well_form.utm_zone }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_utm_hemisphere">{{ well_form.utm_hemisphere.label }}</label>
 | 
						|
                    {{ well_form.utm_hemisphere }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_well_power">{{ well_form.well_power.label }}</label>
 | 
						|
                    {{ well_form.well_power }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6"></div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_reference_letter_number">{{ well_form.reference_letter_number.label }}</label>
 | 
						|
                    {{ well_form.reference_letter_number }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_reference_letter_date">{{ well_form.reference_letter_date.label }}</label>
 | 
						|
                    <input type="text" class="form-control" id="id_reference_letter_date" name="reference_letter_date" placeholder="انتخاب تاریخ" readonly>
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-12">
 | 
						|
                    <label class="form-label" for="id_representative_letter_file">{{ well_form.representative_letter_file.label }}</label>
 | 
						|
                    {{ well_form.representative_letter_file }}
 | 
						|
                    <!-- نمایش فایل موجود -->
 | 
						|
                    <div id="current-file-display" style="display: none; margin-top: 10px;">
 | 
						|
                      <div class="alert alert-info d-flex align-items-center justify-content-between">
 | 
						|
                        <div class="d-flex align-items-center">
 | 
						|
                          <i class="bx bx-file me-2"></i>
 | 
						|
                          <span id="current-file-name" class="text-truncate" style="max-width: 200px;" title=""></span>
 | 
						|
                        </div>
 | 
						|
                        <button type="button" class="btn btn-sm btn-outline-danger" onclick="removeCurrentFile()">
 | 
						|
                          <i class="bx bx-trash me-1"></i>حذف
 | 
						|
                        </button>
 | 
						|
                      </div>
 | 
						|
                    </div>
 | 
						|
                    <input type="hidden" id="remove-file" name="remove_file" value="false">
 | 
						|
                  </div>
 | 
						|
                </div>
 | 
						|
              </div>
 | 
						|
              <hr class="mt-3 border border-dashed">
 | 
						|
              <div class="col-sm-12">
 | 
						|
                <label class="form-label">کد ملی نماینده</label>
 | 
						|
                <div class="input-group">
 | 
						|
                  <input type="text" class="form-control" id="rep_national_code" data-field="national_code" placeholder="مثال: 0012345678" maxlength="10" inputmode="numeric" pattern="\d*">
 | 
						|
                  <button class="btn btn-outline-secondary" type="button" id="btnLookupRep">
 | 
						|
                    بررسی/افزودن نماینده
 | 
						|
                  </button>
 | 
						|
                </div>
 | 
						|
                <div class="form-text" id="repStatus"></div>
 | 
						|
              </div>
 | 
						|
 | 
						|
              <div id="repNewFields" class="col-sm-12" style="display:none;">
 | 
						|
                <div class="row g-3">
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_first_name">{{ customer_form.first_name.label }}</label>
 | 
						|
                    {{ customer_form.first_name }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_last_name">{{ customer_form.last_name.label }}</label>
 | 
						|
                    {{ customer_form.last_name }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_phone_number_1">{{ customer_form.phone_number_1.label }}</label>
 | 
						|
                    {{ customer_form.phone_number_1 }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_phone_number_2">{{ customer_form.phone_number_2.label }}</label>
 | 
						|
                    {{ customer_form.phone_number_2 }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_national_code">{{ customer_form.national_code.label }}</label>
 | 
						|
                    {{ customer_form.national_code }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_card_number">{{ customer_form.card_number.label }}</label>
 | 
						|
                    {{ customer_form.card_number }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_account_number">{{ customer_form.account_number.label }}</label>
 | 
						|
                    {{ customer_form.account_number }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-6">
 | 
						|
                    <label class="form-label" for="id_bank_name">{{ customer_form.bank_name.label }}</label>
 | 
						|
                    {{ customer_form.bank_name }}
 | 
						|
                  </div>
 | 
						|
                  <div class="col-sm-12">
 | 
						|
                    <label class="form-label" for="id_address">{{ customer_form.address.label }}</label>
 | 
						|
                    {{ customer_form.address }}
 | 
						|
                  </div>
 | 
						|
                </div>
 | 
						|
              </div>
 | 
						|
              <hr class="mt-3 border border-dashed">
 | 
						|
              <div class="col-sm-12">
 | 
						|
                <label class="form-label">توضیحات</label>
 | 
						|
                <textarea class="form-control" rows="3" id="req_description" name="description"></textarea>
 | 
						|
              </div>
 | 
						|
            </div>
 | 
						|
          </form>
 | 
						|
        </div>
 | 
						|
        <div class="modal-footer">
 | 
						|
          <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">بستن</button>
 | 
						|
          <button type="button" class="btn btn-primary" id="btnSaveRequest" disabled>ذخیره</button>
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
  </div>
 | 
						|
</div>
 | 
						|
 | 
						|
<!-- Delete Confirmation Modal -->
 | 
						|
<div class="modal fade" id="deleteConfirmModal" tabindex="-1" aria-labelledby="deleteConfirmModalLabel" aria-hidden="true">
 | 
						|
  <div class="modal-dialog">
 | 
						|
    <div class="modal-content">
 | 
						|
      <div class="modal-header">
 | 
						|
        <h5 class="modal-title" id="deleteConfirmModalLabel">تایید حذف</h5>
 | 
						|
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
 | 
						|
      </div>
 | 
						|
      <div class="modal-body">
 | 
						|
        <p id="deleteConfirmText">آیا از حذف این درخواست اطمینان دارید؟</p>
 | 
						|
      </div>
 | 
						|
      <div class="modal-footer">
 | 
						|
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">انصراف</button>
 | 
						|
        <button type="button" class="btn btn-danger" id="confirmDeleteBtn">حذف</button>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
  </div>
 | 
						|
</div>
 | 
						|
{% endblock %}
 | 
						|
 | 
						|
{% block script %}
 | 
						|
<!-- DataTables JS -->
 | 
						|
<script src="{% static 'assets/vendor/libs/datatables-bs5/datatables-bootstrap5.js' %}"></script>
 | 
						|
<!-- Persian DataTable defaults -->
 | 
						|
<script src="{% static 'assets/js/persian-datatable.js' %}"></script>
 | 
						|
 | 
						|
<!-- Persian Date Picker JS -->
 | 
						|
<script src="https://unpkg.com/persian-date@latest/dist/persian-date.min.js"></script>
 | 
						|
<script src="https://unpkg.com/persian-datepicker@latest/dist/js/persian-datepicker.min.js"></script>
 | 
						|
 | 
						|
 | 
						|
<script>
 | 
						|
 | 
						|
  // Function to initialize Persian Date Picker
 | 
						|
  function initPersianDatePicker() {
 | 
						|
    if ($.fn.persianDatepicker && $('#id_reference_letter_date').length) {
 | 
						|
      try {
 | 
						|
        $('#id_reference_letter_date').persianDatepicker({
 | 
						|
          format: 'YYYY/MM/DD',
 | 
						|
          initialValue: false,
 | 
						|
          autoClose: true,
 | 
						|
          persianDigit: false,
 | 
						|
          observer: true,
 | 
						|
          calendar: {
 | 
						|
            persian: {
 | 
						|
              locale: 'fa',
 | 
						|
              leapYearMode: 'astronomical'
 | 
						|
            }
 | 
						|
          },
 | 
						|
          onSelect: function(unix) {
 | 
						|
            // تبدیل تاریخ شمسی به میلادی برای ارسال به سرور
 | 
						|
            const gregorianDate = new Date(unix);
 | 
						|
            const year = gregorianDate.getFullYear();
 | 
						|
            const month = String(gregorianDate.getMonth() + 1).padStart(2, '0');
 | 
						|
            const day = String(gregorianDate.getDate()).padStart(2, '0');
 | 
						|
            const gregorianDateString = `${year}-${month}-${day}`;
 | 
						|
            
 | 
						|
            // نمایش تاریخ شمسی در فیلد
 | 
						|
            if (window.persianDate) {
 | 
						|
              const persianDate = new window.persianDate(unix);
 | 
						|
              const persianDateString = persianDate.format('YYYY/MM/DD');
 | 
						|
              $('#id_reference_letter_date').val(persianDateString);
 | 
						|
            } else {
 | 
						|
              // اگر persianDate در دسترس نبود، تاریخ میلادی را نمایش بده
 | 
						|
              $('#id_reference_letter_date').val(gregorianDateString);
 | 
						|
            }
 | 
						|
            
 | 
						|
            // ذخیره تاریخ میلادی در فیلد مخفی برای ارسال به سرور
 | 
						|
            $('#id_reference_letter_date').attr('data-gregorian', gregorianDateString);
 | 
						|
          }
 | 
						|
        });
 | 
						|
      } catch (e) {
 | 
						|
        console.error('Error initializing Persian Date Picker:', e);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  $(function() {
 | 
						|
    // Initialize DataTable similar to customer_list
 | 
						|
    $('#requests-table').DataTable({
 | 
						|
      pageLength: 10,
 | 
						|
      lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "همه"]],
 | 
						|
      order: [[0, 'desc']],
 | 
						|
      responsive: true,
 | 
						|
    });
 | 
						|
    let currentWellId = null;
 | 
						|
    let currentRepId = null;
 | 
						|
    let wellChecked = false;
 | 
						|
    let repChecked = false;
 | 
						|
 | 
						|
    function setStatus(el, text, type) {
 | 
						|
      $(el).text(text).removeClass('text-danger text-success text-muted').addClass(type ? 'text-' + type : 'text-muted');
 | 
						|
    }
 | 
						|
 | 
						|
    function checkSaveButton() {
 | 
						|
      const canSave = wellChecked && repChecked;
 | 
						|
      $('#btnSaveRequest').prop('disabled', !canSave);
 | 
						|
    }
 | 
						|
 | 
						|
    // Inline error helpers
 | 
						|
    function clearInlineErrors() {
 | 
						|
      $('#requestModal .is-invalid').removeClass('is-invalid');
 | 
						|
      $('#requestModal .invalid-feedback.inline-error').remove();
 | 
						|
    }
 | 
						|
 | 
						|
    function applyErrorTo(selector, message) {
 | 
						|
      const $el = $(selector);
 | 
						|
      if (!$el.length) return false;
 | 
						|
      $el.addClass('is-invalid');
 | 
						|
      const $feedback = $('<div class="invalid-feedback inline-error"></div>').text(message);
 | 
						|
      const $grp = $el.closest('.input-group, .form-group, .mb-3');
 | 
						|
      if ($grp.length) {
 | 
						|
        $feedback.insertAfter($grp);
 | 
						|
      } else {
 | 
						|
        $feedback.insertAfter($el);
 | 
						|
      }
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // Generic field resolution with small exception map
 | 
						|
    const exceptionMap = {
 | 
						|
      water_subscription_number: '#req_water_sub',
 | 
						|
      national_code: '#rep_national_code',
 | 
						|
      representative: '#rep_national_code'
 | 
						|
    };
 | 
						|
 | 
						|
    function findFieldSelector(field, context) {
 | 
						|
      const $ctx = context ? $(context) : $('#requestModal');
 | 
						|
      let $el = $ctx.find(`#id_${field}`).first();
 | 
						|
      if ($el.length) return $el;
 | 
						|
      $el = $ctx.find(`[name="${field}"]`).first();
 | 
						|
      if ($el.length) return $el;
 | 
						|
      $el = $ctx.find(`[data-field="${field}"]`).first();
 | 
						|
      if ($el.length) return $el;
 | 
						|
      const ex = exceptionMap[field];
 | 
						|
      return ex ? $(ex) : $();
 | 
						|
    }
 | 
						|
 | 
						|
    function showInlineErrors(errors) {
 | 
						|
      if (!errors) return;
 | 
						|
      let nonFieldWell = '';
 | 
						|
      let nonFieldCustomer = '';
 | 
						|
      // Request-level errors (e.g., process)
 | 
						|
      if (errors.request) {
 | 
						|
        for (const key in errors.request) {
 | 
						|
          const msgs = Array.isArray(errors.request[key]) ? errors.request[key] : [errors.request[key]];
 | 
						|
          if (key === '__all__' || key === 'non_field_errors') { continue; }
 | 
						|
          applyErrorTo(findFieldSelector(key, '#requestForm'), msgs[0]);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (errors.well) {
 | 
						|
        for (const key in errors.well) {
 | 
						|
          const msgs = Array.isArray(errors.well[key]) ? errors.well[key] : [errors.well[key]];
 | 
						|
          if (key === '__all__' || key === 'non_field_errors') { nonFieldWell = msgs.join('، '); continue; }
 | 
						|
          applyErrorTo(findFieldSelector(key, '#wellFormBlock'), msgs[0]);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (errors.customer) {
 | 
						|
        for (const key in errors.customer) {
 | 
						|
          const msgs = Array.isArray(errors.customer[key]) ? errors.customer[key] : [errors.customer[key]];
 | 
						|
          if (key === '__all__' || key === 'non_field_errors') { nonFieldCustomer = msgs.join('، '); continue; }
 | 
						|
          applyErrorTo(findFieldSelector(key, '#repNewFields'), msgs[0]);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (nonFieldWell) setStatus('#wellStatus', nonFieldWell, 'danger');
 | 
						|
      if (nonFieldCustomer) setStatus('#repStatus', nonFieldCustomer, 'danger');
 | 
						|
    }
 | 
						|
 | 
						|
    $('#btnLookupWell').on('click', function() {
 | 
						|
      const sub = $('#req_water_sub').val().trim();
 | 
						|
      if (!sub) { setStatus('#wellStatus', 'لطفا شماره اشتراک آب را وارد کنید', 'danger'); return; }
 | 
						|
      setStatus('#wellStatus', 'در حال بررسی...', 'muted');
 | 
						|
      wellChecked = true;
 | 
						|
      checkSaveButton();
 | 
						|
      $.get('{% url "processes:lookup_well_by_subscription" %}', { water_subscription_number: sub })
 | 
						|
        .done(function(resp){
 | 
						|
            if (resp.exists) {
 | 
						|
            currentWellId = resp.well.id;
 | 
						|
            $('#wellFormBlock').show();
 | 
						|
            // Initialize Persian Date Picker after well form is shown
 | 
						|
            setTimeout(initPersianDatePicker, 100);
 | 
						|
 | 
						|
            // Prefill well form
 | 
						|
            $('#id_electricity_subscription_number').val(resp.well.electricity_subscription_number || '');
 | 
						|
            $('#id_water_meter_serial_number').val(resp.well.water_meter_serial_number || '');
 | 
						|
            $('#id_water_meter_old_serial_number').val(resp.well.water_meter_old_serial_number || '');
 | 
						|
            $('#id_water_meter_manufacturer').val(resp.well.water_meter_manufacturer || '');
 | 
						|
            $('#id_utm_x').val(resp.well.utm_x || '');
 | 
						|
            $('#id_utm_y').val(resp.well.utm_y || '');
 | 
						|
            $('#id_utm_zone').val(resp.well.utm_zone || '');
 | 
						|
            $('#id_utm_hemisphere').val(resp.well.utm_hemisphere || '');
 | 
						|
            $('#id_well_power').val(resp.well.well_power || '');
 | 
						|
            $('#id_reference_letter_number').val(resp.well.reference_letter_number || '');
 | 
						|
            // Prefill date: show Persian in input, keep Gregorian in data attribute
 | 
						|
            if (resp.well.reference_letter_date) {
 | 
						|
              try {
 | 
						|
                if (window.persianDate) {
 | 
						|
                  const gregorianDate = new Date(resp.well.reference_letter_date);
 | 
						|
                  const persianDateObj = new window.persianDate(gregorianDate);
 | 
						|
                  const persianDateString = persianDateObj.format('YYYY/MM/DD');
 | 
						|
                  $('#id_reference_letter_date').val(persianDateString);
 | 
						|
                } else {
 | 
						|
                  $('#id_reference_letter_date').val(resp.well.reference_letter_date);
 | 
						|
                }
 | 
						|
                $('#id_reference_letter_date').attr('data-gregorian', resp.well.reference_letter_date);
 | 
						|
              } catch (e) {
 | 
						|
                $('#id_reference_letter_date').val(resp.well.reference_letter_date);
 | 
						|
              }
 | 
						|
            } else {
 | 
						|
              $('#id_reference_letter_date').val('');
 | 
						|
              $('#id_reference_letter_date').removeAttr('data-gregorian');
 | 
						|
            }
 | 
						|
              // Existing representative letter file display
 | 
						|
              if (resp.well.representative_letter_file_url) {
 | 
						|
                $('#current-file-display').show();
 | 
						|
                const fileName = resp.well.representative_letter_file_name || 'فایل موجود';
 | 
						|
                $('#current-file-name').text(fileName).attr('title', fileName);
 | 
						|
                $('#id_representative_letter_file').hide();
 | 
						|
                $('#remove-file').val('false');
 | 
						|
              } else {
 | 
						|
                $('#current-file-display').hide();
 | 
						|
                $('#id_representative_letter_file').show();
 | 
						|
                $('#remove-file').val('false');
 | 
						|
              }
 | 
						|
            setStatus('#wellStatus', 'چاه یافت شد', 'success');
 | 
						|
          } else {
 | 
						|
            currentWellId = null;
 | 
						|
            $('#wellFormBlock').show();
 | 
						|
            $('#wellFormBlock').find('input, select').val('');
 | 
						|
            $('#id_reference_letter_date').removeAttr('data-gregorian');
 | 
						|
              // Reset file UI for new well
 | 
						|
              $('#current-file-display').hide();
 | 
						|
              $('#id_representative_letter_file').show().val('');
 | 
						|
              $('#remove-file').val('false');
 | 
						|
            // Initialize Persian Date Picker after well form is shown
 | 
						|
            setTimeout(initPersianDatePicker, 100);
 | 
						|
            setStatus('#wellStatus', 'چاه یافت نشد. اطلاعات چاه را وارد کنید.', 'danger');
 | 
						|
          }
 | 
						|
        })
 | 
						|
        .fail(function(){ setStatus('#wellStatus', 'خطا در بررسی چاه', 'danger'); });
 | 
						|
    });
 | 
						|
 | 
						|
    $('#btnLookupRep').on('click', function() {
 | 
						|
      const nc = $('#rep_national_code').val().trim();
 | 
						|
      if (!nc) { setStatus('#repStatus', 'لطفا کد ملی نماینده را وارد کنید', 'danger'); return; }
 | 
						|
      setStatus('#repStatus', 'در حال بررسی...', 'muted');
 | 
						|
      repChecked = true;
 | 
						|
      checkSaveButton();
 | 
						|
      $.get('{% url "processes:lookup_representative_by_national_code" %}', { national_code: nc })
 | 
						|
        .done(function(resp){
 | 
						|
          if (resp.exists) {
 | 
						|
            currentRepId = resp.user.id;
 | 
						|
            $('#repNewFields').show();
 | 
						|
            // Prefill customer form fields for editing
 | 
						|
            $('#id_first_name').val(resp.user.first_name || '');
 | 
						|
            $('#id_last_name').val(resp.user.last_name || '');
 | 
						|
            if (resp.user.profile) {
 | 
						|
              $('#id_national_code').val(resp.user.profile.national_code || nc);
 | 
						|
              $('#id_phone_number_1').val(resp.user.profile.phone_number_1 || '');
 | 
						|
              $('#id_phone_number_2').val(resp.user.profile.phone_number_2 || '');
 | 
						|
              $('#id_card_number').val(resp.user.profile.card_number || '');
 | 
						|
              $('#id_account_number').val(resp.user.profile.account_number || '');
 | 
						|
              $('#id_bank_name').val(resp.user.profile.bank_name || '');
 | 
						|
              $('#id_address').val(resp.user.profile.address || '');
 | 
						|
            } else {
 | 
						|
              $('#id_national_code').val(nc);
 | 
						|
              $('#id_phone_number_1').val('');
 | 
						|
              $('#id_phone_number_2').val('');
 | 
						|
              $('#id_card_number').val('');
 | 
						|
              $('#id_account_number').val('');
 | 
						|
              $('#id_bank_name').val('');
 | 
						|
              $('#id_address').val('');
 | 
						|
            }
 | 
						|
            setStatus('#repStatus', 'نماینده یافت شد.', 'success');
 | 
						|
          } else {
 | 
						|
            currentRepId = null;
 | 
						|
            $('#repNewFields').show();
 | 
						|
            // Clear form and prefill national code
 | 
						|
            $('#id_first_name').val('');
 | 
						|
            $('#id_last_name').val('');
 | 
						|
            $('#id_national_code').val(nc);
 | 
						|
            $('#id_phone_number_1').val('');
 | 
						|
            $('#id_phone_number_2').val('');
 | 
						|
            $('#id_card_number').val('');
 | 
						|
            $('#id_account_number').val('');
 | 
						|
            $('#id_bank_name').val('');
 | 
						|
            $('#id_address').val('');
 | 
						|
            setStatus('#repStatus', 'نماینده یافت نشد. لطفا اطلاعات را تکمیل کنید.', 'danger');
 | 
						|
          }
 | 
						|
        })
 | 
						|
        .fail(function(){ setStatus('#repStatus', 'خطا در بررسی نماینده', 'danger'); });
 | 
						|
    });
 | 
						|
 | 
						|
    $('#btnSaveRequest').on('click', function(){
 | 
						|
      clearInlineErrors();
 | 
						|
      // Use form's native FormData - much cleaner!
 | 
						|
      const formData = new FormData(document.getElementById('requestForm'));
 | 
						|
      
 | 
						|
      // Add custom fields that aren't in the form
 | 
						|
      if (currentWellId) formData.append('well_id', currentWellId);
 | 
						|
      if (currentRepId) formData.append('representative_id', currentRepId);
 | 
						|
      
 | 
						|
      // Handle special national_code logic (prefer visible field)
 | 
						|
      const ncField = $('#id_national_code').val();
 | 
						|
      if (ncField) {
 | 
						|
        formData.set('national_code', ncField);
 | 
						|
      } else {
 | 
						|
        formData.set('national_code', $('#rep_national_code').val().trim());
 | 
						|
      }
 | 
						|
      
 | 
						|
      // Handle Persian date conversion
 | 
						|
      const gregorianDate = $('#id_reference_letter_date').attr('data-gregorian');
 | 
						|
      if (gregorianDate) {
 | 
						|
        formData.set('reference_letter_date', gregorianDate);
 | 
						|
      }
 | 
						|
 | 
						|
      const $btn = $(this).prop('disabled', true).text('در حال ذخیره...');
 | 
						|
      $.ajax({
 | 
						|
        url: '{% url "processes:create_request_with_entities" %}',
 | 
						|
        method: 'POST',
 | 
						|
        data: formData,
 | 
						|
        processData: false,
 | 
						|
        contentType: false,
 | 
						|
      }).done(function(resp){
 | 
						|
        if (resp.ok) {
 | 
						|
          showToast('درخواست با موفقیت ثبت شد', 'success');
 | 
						|
          if (resp.redirect) {
 | 
						|
            setTimeout(function(){ window.location.href = resp.redirect; }, 800);
 | 
						|
          } else {
 | 
						|
            setTimeout(function(){ location.reload(); }, 1200);
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          clearInlineErrors();
 | 
						|
          if (resp.errors) {
 | 
						|
            showInlineErrors(resp.errors);
 | 
						|
          }
 | 
						|
          const msg = buildErrorMessage(resp);
 | 
						|
          showToast(msg, 'danger');
 | 
						|
        }
 | 
						|
      }).fail(function(xhr){
 | 
						|
        let msg = 'خطا در ذخیره';
 | 
						|
        try {
 | 
						|
          const resp = JSON.parse(xhr.responseText);
 | 
						|
          clearInlineErrors();
 | 
						|
          if (resp && resp.errors) {
 | 
						|
            showInlineErrors(resp.errors);
 | 
						|
          }
 | 
						|
          msg = buildErrorMessage(resp) || msg;
 | 
						|
        } catch(e) {}
 | 
						|
        showToast(msg, 'danger');
 | 
						|
      }).always(function(){
 | 
						|
        $btn.prop('disabled', false).text('ذخیره');
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    function buildErrorMessage(resp){
 | 
						|
      if (!resp) return '';
 | 
						|
      if (resp.error) return resp.error;
 | 
						|
      if (resp.errors) {
 | 
						|
        // Collect form-related errors
 | 
						|
        const parts = [];
 | 
						|
        if (resp.errors.customer) {
 | 
						|
          parts.push('خطای نماینده: ' + flattenErrors(resp.errors.customer));
 | 
						|
        }
 | 
						|
        if (resp.errors.well) {
 | 
						|
          parts.push('خطای چاه: ' + flattenErrors(resp.errors.well));
 | 
						|
        }
 | 
						|
        return parts.join(' | ');
 | 
						|
      }
 | 
						|
      return '';
 | 
						|
    }
 | 
						|
 | 
						|
    function flattenErrors(errorsObj){
 | 
						|
      if (typeof errorsObj === 'string') return errorsObj;
 | 
						|
      try {
 | 
						|
        const parts = [];
 | 
						|
        for (const k in errorsObj){
 | 
						|
          const v = errorsObj[k];
 | 
						|
          if (Array.isArray(v)) parts.push(`${k}: ${v[0]}`);
 | 
						|
          else if (typeof v === 'string') parts.push(`${k}: ${v}`);
 | 
						|
        }
 | 
						|
        return parts.join('، ');
 | 
						|
      } catch(e){
 | 
						|
        return '';
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    $('#btnToggleManufacturer').on('click', function() {
 | 
						|
      const $select = $('#id_water_meter_manufacturer');
 | 
						|
      const $input = $('#id_new_manufacturer');
 | 
						|
      const $btn = $(this);
 | 
						|
      
 | 
						|
      if ($select.is(':visible')) {
 | 
						|
        $select.hide();
 | 
						|
        $input.show().focus();
 | 
						|
        $btn.html('<i class="bx bx-check"></i>');
 | 
						|
      } else {
 | 
						|
        $input.hide();
 | 
						|
        $select.show();
 | 
						|
        $btn.html('<i class="bx bx-plus"></i>');
 | 
						|
      }
 | 
						|
    });
 | 
						|
 | 
						|
    // Enforce digit-only and max length for national code input
 | 
						|
    $('#rep_national_code').on('input', function() {
 | 
						|
      const cleaned = (this.value || '').replace(/\D/g, '').slice(0, 10);
 | 
						|
      if (this.value !== cleaned) {
 | 
						|
        this.value = cleaned;
 | 
						|
      }
 | 
						|
    });
 | 
						|
 | 
						|
    $('#requestModal').on('hidden.bs.modal', function(){
 | 
						|
      $('#requestForm')[0].reset();
 | 
						|
      $('#wellFormBlock').hide();
 | 
						|
      $('#repNewFields').hide();
 | 
						|
      $('#id_reference_letter_date').removeAttr('data-gregorian');
 | 
						|
      // Reset file UI
 | 
						|
      $('#current-file-display').hide();
 | 
						|
      $('#id_representative_letter_file').show().val('');
 | 
						|
      $('#remove-file').val('false');
 | 
						|
      setStatus('#wellStatus', '', '');
 | 
						|
      setStatus('#repStatus', '', '');
 | 
						|
      currentWellId = null;
 | 
						|
      currentRepId = null;
 | 
						|
      wellChecked = false;
 | 
						|
      repChecked = false;
 | 
						|
      checkSaveButton();
 | 
						|
      clearInlineErrors(); // Clear inline errors on modal close
 | 
						|
    });
 | 
						|
 | 
						|
    // Handle selecting a new file: hide existing file display and cancel removal flag
 | 
						|
    $('#id_representative_letter_file').on('change', function() {
 | 
						|
      if (this.files && this.files.length > 0) {
 | 
						|
        $('#current-file-display').hide();
 | 
						|
        $('#remove-file').val('false');
 | 
						|
      }
 | 
						|
    });
 | 
						|
 | 
						|
    // Expose remove function
 | 
						|
    window.removeCurrentFile = function() {
 | 
						|
      $('#current-file-display').hide();
 | 
						|
      $('#remove-file').val('true');
 | 
						|
      $('#id_representative_letter_file').show().val('');
 | 
						|
    };
 | 
						|
 | 
						|
    // Delete request function
 | 
						|
    window.deleteRequest = function(instanceId, instanceCode) {
 | 
						|
      // Set modal content
 | 
						|
      document.getElementById('deleteConfirmText').textContent = `آیا از حذف درخواست ${instanceCode} اطمینان دارید؟`;
 | 
						|
      
 | 
						|
      // Show modal
 | 
						|
      const modal = new bootstrap.Modal(document.getElementById('deleteConfirmModal'));
 | 
						|
      modal.show();
 | 
						|
      
 | 
						|
      // Handle confirm button click
 | 
						|
      document.getElementById('confirmDeleteBtn').onclick = function() {
 | 
						|
        $.ajax({
 | 
						|
          url: '{% url "processes:delete_request" 0 %}'.replace('0', instanceId),
 | 
						|
          type: 'POST',
 | 
						|
          data: {
 | 
						|
            'csrfmiddlewaretoken': $('[name=csrfmiddlewaretoken]').val()
 | 
						|
          },
 | 
						|
          success: function(response) {
 | 
						|
            if (response.success) {
 | 
						|
              showToast(response.message, 'success');
 | 
						|
              modal.hide();
 | 
						|
              setTimeout(() => {
 | 
						|
                window.location.reload();
 | 
						|
              }, 1500);
 | 
						|
            } else {
 | 
						|
              showToast(response.message, 'danger');
 | 
						|
            }
 | 
						|
          },
 | 
						|
          error: function() {
 | 
						|
            showToast('خطا در ارتباط با سرور', 'danger');
 | 
						|
          }
 | 
						|
        });
 | 
						|
      };
 | 
						|
    };
 | 
						|
  });
 | 
						|
</script>
 | 
						|
{% endblock %}
 | 
						|
 | 
						|
 |