complete first version of main proccess
This commit is contained in:
		
							parent
							
								
									6ff4740d04
								
							
						
					
					
						commit
						f2fc2362a7
					
				
					 61 changed files with 3280 additions and 28 deletions
				
			
		
							
								
								
									
										55
									
								
								invoices/templates/invoices/final_invoice_print.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								invoices/templates/invoices/final_invoice_print.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,55 @@
 | 
			
		|||
{% extends '_base.html' %}
 | 
			
		||||
{% load humanize %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="container py-4">
 | 
			
		||||
  <div class="mb-4 d-flex justify-content-between align-items-center">
 | 
			
		||||
    <div>
 | 
			
		||||
      <h4 class="mb-1">فاکتور نهایی</h4>
 | 
			
		||||
      <small class="text-muted">کد درخواست: {{ instance.code }}</small>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div>
 | 
			
		||||
      <!-- Placeholders for logo/signature -->
 | 
			
		||||
      <div class="text-end">لوگو</div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="table-responsive">
 | 
			
		||||
    <table class="table table-bordered">
 | 
			
		||||
      <thead>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <th>آیتم</th>
 | 
			
		||||
          <th>تعداد</th>
 | 
			
		||||
          <th>قیمت واحد</th>
 | 
			
		||||
          <th>قیمت کل</th>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </thead>
 | 
			
		||||
      <tbody>
 | 
			
		||||
        {% for it in items %}
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td>{{ it.item.name }}</td>
 | 
			
		||||
          <td>{{ it.quantity }}</td>
 | 
			
		||||
          <td>{{ it.unit_price|floatformat:0|intcomma:False }}</td>
 | 
			
		||||
          <td>{{ it.total_price|floatformat:0|intcomma:False }}</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        {% empty %}
 | 
			
		||||
        <tr><td colspan="4" class="text-center text-muted">آیتمی ندارد</td></tr>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
      </tbody>
 | 
			
		||||
      <tfoot>
 | 
			
		||||
        <tr><th colspan="3" class="text-end">مبلغ کل</th><th>{{ invoice.total_amount|floatformat:0|intcomma:False }}</th></tr>
 | 
			
		||||
        <tr><th colspan="3" class="text-end">تخفیف</th><th>{{ invoice.discount_amount|floatformat:0|intcomma:False }}</th></tr>
 | 
			
		||||
        <tr><th colspan="3" class="text-end">مبلغ نهایی</th><th>{{ invoice.final_amount|floatformat:0|intcomma:False }}</th></tr>
 | 
			
		||||
        <tr><th colspan="3" class="text-end">پرداختیها</th><th>{{ invoice.paid_amount|floatformat:0|intcomma:False }}</th></tr>
 | 
			
		||||
        <tr><th colspan="3" class="text-end">مانده</th><th>{{ invoice.remaining_amount|floatformat:0|intcomma:False }}</th></tr>
 | 
			
		||||
      </tfoot>
 | 
			
		||||
    </table>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="mt-5 d-flex justify-content-between">
 | 
			
		||||
    <div>امضا مشتری</div>
 | 
			
		||||
    <div>امضا شرکت</div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
<script>window.print()</script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										260
									
								
								invoices/templates/invoices/final_invoice_step.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								invoices/templates/invoices/final_invoice_step.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,260 @@
 | 
			
		|||
{% extends '_base.html' %}
 | 
			
		||||
{% load static %}
 | 
			
		||||
{% load processes_tags %}
 | 
			
		||||
{% load humanize %}
 | 
			
		||||
 | 
			
		||||
{% block sidebar %}
 | 
			
		||||
    {% include 'sidebars/admin.html' %}
 | 
			
		||||
{% endblock sidebar %}
 | 
			
		||||
 | 
			
		||||
{% block navbar %}
 | 
			
		||||
    {% include 'navbars/admin.html' %}
 | 
			
		||||
{% endblock navbar %}
 | 
			
		||||
 | 
			
		||||
{% block title %}{{ step.name }} - درخواست {{ instance.code }}{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block style %}
 | 
			
		||||
<link rel="stylesheet" href="{% static 'assets/vendor/libs/bs-stepper/bs-stepper.css' %}">
 | 
			
		||||
<style>
 | 
			
		||||
@media print {
 | 
			
		||||
  .no-print { display: none !important; }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% include '_toasts.html' %}
 | 
			
		||||
{% csrf_token %}
 | 
			
		||||
<div class="container-xxl flex-grow-1 container-p-y">
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <div class="col-12 mb-4">
 | 
			
		||||
      <div class="d-flex align-items-center justify-content-between mb-3 no-print">
 | 
			
		||||
        <div>
 | 
			
		||||
          <h4 class="mb-1">{{ step.name }}: {{ instance.process.name }}</h4>
 | 
			
		||||
          <small class="text-muted d-block">
 | 
			
		||||
            اشتراک آب: {{ instance.well.water_subscription_number|default:"-" }}
 | 
			
		||||
            | نماینده: {{ instance.representative.profile.national_code|default:"-" }}
 | 
			
		||||
          </small>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="d-flex gap-2">
 | 
			
		||||
        <a href="{% url 'invoices:final_invoice_print' instance.id %}" target="_blank" class="btn btn-outline-secondary"><i class="bx bx-printer"></i> پرینت</a>
 | 
			
		||||
 | 
			
		||||
          <a href="{% url 'processes:request_list' %}" class="btn btn-outline-secondary">بازگشت</a>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="bs-stepper wizard-vertical vertical mt-2 no-print">
 | 
			
		||||
        {% stepper_header instance step %}
 | 
			
		||||
        <div class="bs-stepper-content">
 | 
			
		||||
 | 
			
		||||
      <div class="card border">
 | 
			
		||||
        <div class="card-header d-flex justify-content-between align-items-center">
 | 
			
		||||
          <h5 class="mb-0">فاکتور نهایی</h5>
 | 
			
		||||
          <button type="button" class="btn btn-sm btn-outline-primary" onclick="openSpecialChargeModal()"><i class="bx bx-plus"></i> افزودن هزینه تعمیر/تعویض</button>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <div class="row g-3 mb-3">
 | 
			
		||||
            <div class="col-6 col-md-3">
 | 
			
		||||
              <div class="border rounded p-3 h-100">
 | 
			
		||||
                <div class="small text-muted">مبلغ نهایی</div>
 | 
			
		||||
                <div class="h5 mt-1">{{ invoice.final_amount|floatformat:0|intcomma:False }} تومان</div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-6 col-md-3">
 | 
			
		||||
              <div class="border rounded p-3 h-100">
 | 
			
		||||
                <div class="small text-muted">پرداختیها</div>
 | 
			
		||||
                <div class="h5 mt-1 text-success">{{ invoice.paid_amount|floatformat:0|intcomma:False }} تومان</div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-6 col-md-3">
 | 
			
		||||
              <div class="border rounded p-3 h-100">
 | 
			
		||||
                <div class="small text-muted">مانده</div>
 | 
			
		||||
                <div class="h5 mt-1 {% if invoice.remaining_amount <= 0 %}text-success{% else %}text-danger{% endif %}">{{ invoice.remaining_amount|floatformat:0|intcomma:False }} تومان</div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-6 col-md-3 d-flex align-items-center">
 | 
			
		||||
              {% if invoice.remaining_amount <= 0 %}
 | 
			
		||||
                <span class="badge bg-success">تسویه کامل</span>
 | 
			
		||||
              {% else %}
 | 
			
		||||
                <span class="badge bg-warning text-dark">باقیمانده دارد</span>
 | 
			
		||||
              {% endif %}
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="table-responsive">
 | 
			
		||||
            <table class="table table-striped">
 | 
			
		||||
              <thead>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <th>آیتم</th>
 | 
			
		||||
                  <th class="text-center">تعداد پایه</th>
 | 
			
		||||
                  <th class="text-center">افزوده</th>
 | 
			
		||||
                  <th class="text-center">حذف</th>
 | 
			
		||||
                  <th class="text-center">تعداد نهایی</th>
 | 
			
		||||
                  <th class="text-end">قیمت واحد (تومان)</th>
 | 
			
		||||
                  <th class="text-end">قیمت کل (تومان)</th>
 | 
			
		||||
                </tr>
 | 
			
		||||
              </thead>
 | 
			
		||||
              <tbody>
 | 
			
		||||
                {% for r in rows %}
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <td>
 | 
			
		||||
                    <div class="d-flex flex-column">
 | 
			
		||||
                      <span class="fw-semibold">{{ r.item.name }}</span>
 | 
			
		||||
                      {% if r.item.description %}<small class="text-muted">{{ r.item.description }}</small>{% endif %}
 | 
			
		||||
                    </div>
 | 
			
		||||
                  </td>
 | 
			
		||||
                  <td class="text-center">{{ r.base_qty }}</td>
 | 
			
		||||
                  <td class="text-center text-success">{{ r.added_qty }}</td>
 | 
			
		||||
                  <td class="text-center text-danger">{{ r.removed_qty }}</td>
 | 
			
		||||
                  <td class="text-center">{{ r.quantity }}</td>
 | 
			
		||||
                  <td class="text-end">{{ r.unit_price|floatformat:0|intcomma:False }}</td>
 | 
			
		||||
                  <td class="text-end">{{ r.total_price|floatformat:0|intcomma:False }}</td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                {% empty %}
 | 
			
		||||
                <tr><td colspan="7" class="text-center text-muted">آیتمی یافت نشد</td></tr>
 | 
			
		||||
                {% endfor %}
 | 
			
		||||
                {% for si in invoice_specials %}
 | 
			
		||||
                <tr class="table-warning">
 | 
			
		||||
                  <td>
 | 
			
		||||
                    <div class="d-flex flex-column">
 | 
			
		||||
                      <span class="fw-semibold">{{ si.item.name }}<span class="badge bg-info mx-2">ویژه</span></span>                      
 | 
			
		||||
                    </div>
 | 
			
		||||
                  </td>
 | 
			
		||||
                  <td class="text-center">-</td>
 | 
			
		||||
                  <td class="text-center">-</td>
 | 
			
		||||
                  <td class="text-center">-</td>
 | 
			
		||||
                  <td class="text-center">{{ si.quantity }}</td>
 | 
			
		||||
                  <td class="text-end">{{ si.unit_price|floatformat:0|intcomma:False }}</td>
 | 
			
		||||
                  <td class="text-end">
 | 
			
		||||
                    {{ si.total_price|floatformat:0|intcomma:False }}
 | 
			
		||||
                    <button type="button" class="btn btn-sm btn-outline-danger ms-2" onclick="deleteSpecial('{{ si.id }}')" title="حذف"><i class="bx bx-trash"></i></button>
 | 
			
		||||
                  </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                {% endfor %}
 | 
			
		||||
              </tbody>
 | 
			
		||||
              <tfoot>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <th colspan="6" class="text-end">مبلغ کل</th>
 | 
			
		||||
                  <th class="text-end">{{ invoice.total_amount|floatformat:0|intcomma:False }} تومان</th>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <th colspan="6" class="text-end">تخفیف</th>
 | 
			
		||||
                  <th class="text-end">{{ invoice.discount_amount|floatformat:0|intcomma:False }} تومان</th>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <th colspan="6" class="text-end">مبلغ نهایی</th>
 | 
			
		||||
                  <th class="text-end">{{ invoice.final_amount|floatformat:0|intcomma:False }} تومان</th>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <th colspan="6" class="text-end">پرداختیها</th>
 | 
			
		||||
                  <th class="text-end">{{ invoice.paid_amount|floatformat:0|intcomma:False }} تومان</th>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <th colspan="6" class="text-end">مانده</th>
 | 
			
		||||
                  <th class="text-end {% if invoice.remaining_amount <= 0 %}text-success{% else %}text-danger{% endif %}">{{ invoice.remaining_amount|floatformat:0|intcomma:False }} تومان</th>
 | 
			
		||||
                </tr>
 | 
			
		||||
              </tfoot>
 | 
			
		||||
            </table>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-footer d-flex justify-content-between">
 | 
			
		||||
          {% if previous_step %}
 | 
			
		||||
            <a href="{% url 'processes:step_detail' instance.id previous_step.id %}" class="btn btn-label-secondary">قبلی</a>
 | 
			
		||||
          {% else %}
 | 
			
		||||
            <span></span>
 | 
			
		||||
          {% endif %}
 | 
			
		||||
          {% if next_step %}
 | 
			
		||||
            <button type="button" class="btn btn-primary" id="btnApproveFinalInvoice">تایید و ادامه</button>
 | 
			
		||||
          {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
<!-- Special Charge Modal -->
 | 
			
		||||
<div class="modal fade" id="specialChargeModal" tabindex="-1" aria-labelledby="specialChargeModalLabel" aria-hidden="true">
 | 
			
		||||
  <div class="modal-dialog">
 | 
			
		||||
    <div class="modal-content">
 | 
			
		||||
      <div class="modal-header">
 | 
			
		||||
        <h5 class="modal-title" id="specialChargeModalLabel">افزودن هزینه تعمیر/تعویض</h5>
 | 
			
		||||
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="modal-body">
 | 
			
		||||
        <form id="specialChargeForm" onsubmit="return false;">
 | 
			
		||||
          {% csrf_token %}
 | 
			
		||||
          <div class="mb-3">
 | 
			
		||||
            <label class="form-label">انتخاب آیتم ویژه</label>
 | 
			
		||||
            <select class="form-select" name="item_id" id="id_special_item" required>
 | 
			
		||||
              <option value="">انتخاب کنید...</option>
 | 
			
		||||
              {% for s in special_choices %}
 | 
			
		||||
                <option value="{{ s.id }}">{{ s.name }}</option>
 | 
			
		||||
              {% endfor %}
 | 
			
		||||
            </select>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="mb-3">
 | 
			
		||||
            <label class="form-label">مبلغ (تومان)</label>
 | 
			
		||||
            <input type="number" class="form-control" name="amount" id="id_charge_amount" min="1" required>
 | 
			
		||||
          </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" onclick="submitSpecialCharge()">افزودن</button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block script %}
 | 
			
		||||
<script>
 | 
			
		||||
  function openSpecialChargeModal(){
 | 
			
		||||
    const el = document.getElementById('specialChargeModal');
 | 
			
		||||
    if (window.$ && typeof $(el).modal === 'function') { $(el).modal('show'); }
 | 
			
		||||
    else if (window.bootstrap && window.bootstrap.Modal) { new window.bootstrap.Modal(el).show(); }
 | 
			
		||||
    else { el.classList.add('show'); el.style.display = 'block'; }
 | 
			
		||||
  }
 | 
			
		||||
  function submitSpecialCharge(){
 | 
			
		||||
    const fd = new FormData(document.getElementById('specialChargeForm'));
 | 
			
		||||
    fd.append('csrfmiddlewaretoken', document.querySelector('input[name=csrfmiddlewaretoken]').value);
 | 
			
		||||
    fetch('{% url "invoices:add_special_charge" instance.id step.id %}', { method: 'POST', body: fd })
 | 
			
		||||
      .then(r=>r.json()).then(resp=>{
 | 
			
		||||
        if (resp.success){
 | 
			
		||||
          showToast('هزینه ویژه اضافه شد', 'success');
 | 
			
		||||
          if (resp.redirect) setTimeout(()=>{ window.location.href = resp.redirect; }, 600);
 | 
			
		||||
        } else {
 | 
			
		||||
          showToast(resp.message || 'خطا در افزودن هزینه', 'danger');
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(()=> showToast('خطا در ارتباط با سرور', 'danger'));
 | 
			
		||||
  }
 | 
			
		||||
  // No filtering needed; show all special items
 | 
			
		||||
  function deleteSpecial(id){
 | 
			
		||||
    const fd = new FormData();
 | 
			
		||||
    fd.append('csrfmiddlewaretoken', document.querySelector('input[name=csrfmiddlewaretoken]').value);
 | 
			
		||||
    fetch(`{% url "invoices:delete_special_charge" instance.id step.id 0 %}`.replace('/0/', `/${id}/`), { method: 'POST', body: fd })
 | 
			
		||||
      .then(r=>r.json()).then(resp=>{
 | 
			
		||||
        if (resp.success){
 | 
			
		||||
          showToast('حذف شد', 'success');
 | 
			
		||||
          if (resp.redirect) setTimeout(()=>{ window.location.href = resp.redirect; }, 500);
 | 
			
		||||
        } else {
 | 
			
		||||
          showToast(resp.message || 'خطا در حذف', 'danger');
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(()=> showToast('خطا در ارتباط با سرور', 'danger'));
 | 
			
		||||
  }
 | 
			
		||||
  document.getElementById('btnApproveFinalInvoice')?.addEventListener('click', function(){
 | 
			
		||||
    const fd = new FormData();
 | 
			
		||||
    fd.append('csrfmiddlewaretoken', document.querySelector('input[name=csrfmiddlewaretoken]').value);
 | 
			
		||||
    fetch('{% url "invoices:approve_final_invoice" instance.id step.id %}', { method:'POST', body: fd })
 | 
			
		||||
      .then(r=>r.json()).then(resp=>{
 | 
			
		||||
        if (resp.success){
 | 
			
		||||
          showToast(resp.message || 'تایید شد', 'success');
 | 
			
		||||
          if (resp.redirect) setTimeout(()=>{ window.location.href = resp.redirect; }, 600);
 | 
			
		||||
        } else {
 | 
			
		||||
          showToast(resp.message || 'خطا در تایید', 'danger');
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(()=> showToast('خطا در ارتباط با سرور', 'danger'));
 | 
			
		||||
  });
 | 
			
		||||
</script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										248
									
								
								invoices/templates/invoices/final_settlement_step.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								invoices/templates/invoices/final_settlement_step.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,248 @@
 | 
			
		|||
{% extends '_base.html' %}
 | 
			
		||||
{% load static %}
 | 
			
		||||
{% load processes_tags %}
 | 
			
		||||
{% load common_tags %}
 | 
			
		||||
{% load humanize %}
 | 
			
		||||
 | 
			
		||||
{% block sidebar %}
 | 
			
		||||
    {% include 'sidebars/admin.html' %}
 | 
			
		||||
{% endblock sidebar %}
 | 
			
		||||
 | 
			
		||||
{% block navbar %}
 | 
			
		||||
    {% include 'navbars/admin.html' %}
 | 
			
		||||
{% endblock navbar %}
 | 
			
		||||
 | 
			
		||||
{% block title %}{{ step.name }} - درخواست {{ instance.code }}{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block style %}
 | 
			
		||||
<link rel="stylesheet" href="{% static 'assets/vendor/libs/bs-stepper/bs-stepper.css' %}">
 | 
			
		||||
<!-- Persian Date Picker CSS -->
 | 
			
		||||
<link rel="stylesheet" href="https://unpkg.com/persian-datepicker@latest/dist/css/persian-datepicker.min.css">
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% include '_toasts.html' %}
 | 
			
		||||
{% csrf_token %}
 | 
			
		||||
<div class="container-xxl flex-grow-1 container-p-y">
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <div class="col-12 mb-4">
 | 
			
		||||
      <div class="d-flex align-items-center justify-content-between mb-3 no-print">
 | 
			
		||||
        <div>
 | 
			
		||||
          <h4 class="mb-1">{{ step.name }}: {{ instance.process.name }}</h4>
 | 
			
		||||
          <small class="text-muted d-block">
 | 
			
		||||
            اشتراک آب: {{ instance.well.water_subscription_number|default:"-" }}
 | 
			
		||||
            | نماینده: {{ instance.representative.profile.national_code|default:"-" }}
 | 
			
		||||
          </small>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="d-flex gap-2">
 | 
			
		||||
          <a href="{% url 'invoices:final_invoice_print' instance.id %}" target="_blank" class="btn btn-outline-secondary"><i class="bx bx-printer"></i> پرینت</a>
 | 
			
		||||
 | 
			
		||||
          <a href="{% url 'processes:request_list' %}" class="btn btn-outline-secondary">بازگشت</a>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="bs-stepper wizard-vertical vertical mt-2 no-print">
 | 
			
		||||
        {% stepper_header instance step %}
 | 
			
		||||
        <div class="bs-stepper-content">
 | 
			
		||||
 | 
			
		||||
      <div class="row g-3">
 | 
			
		||||
        <div class="col-12 col-lg-5">
 | 
			
		||||
          <div class="card border h-100">
 | 
			
		||||
            <div class="card-header"><h5 class="mb-0">ثبت تراکنش تسویه</h5></div>
 | 
			
		||||
            <div class="card-body">
 | 
			
		||||
              <form id="formFinalPayment" enctype="multipart/form-data" onsubmit="return false;">
 | 
			
		||||
                {% csrf_token %}
 | 
			
		||||
                <div class="mb-3">
 | 
			
		||||
                  <label class="form-label">نوع تراکنش</label>
 | 
			
		||||
                  <select class="form-select" name="direction" id="id_direction" required>
 | 
			
		||||
                    <option value="in">دریافتی از مشتری</option>
 | 
			
		||||
                    <option value="out">پرداخت به مشتری</option>
 | 
			
		||||
                  </select>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="mb-3">
 | 
			
		||||
                  <label class="form-label">مبلغ (تومان)</label>
 | 
			
		||||
                  <input type="number" min="1" class="form-control" name="amount" id="id_amount" required>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="mb-3">
 | 
			
		||||
                  <label class="form-label">تاریخ</label>
 | 
			
		||||
                  <input type="text" class="form-control" id="id_payment_date" name="payment_date" placeholder="انتخاب تاریخ" readonly required>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="mb-3">
 | 
			
		||||
                  <label class="form-label">روش پرداخت</label>
 | 
			
		||||
                  <select class="form-select" name="payment_method" id="id_payment_method" required>
 | 
			
		||||
                    <option value="bank_transfer">انتقال بانکی</option>
 | 
			
		||||
                    <option value="card">کارت بانکی</option>
 | 
			
		||||
                    <option value="cash">نقدی</option>
 | 
			
		||||
                    <option value="check">چک</option>
 | 
			
		||||
                    <option value="other">سایر</option>
 | 
			
		||||
                  </select>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="mb-3">
 | 
			
		||||
                  <label class="form-label">شماره مرجع</label>
 | 
			
		||||
                  <input type="text" class="form-control" name="reference_number" id="id_reference_number" required>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="mb-3">
 | 
			
		||||
                  <label class="form-label">تصویر فیش</label>
 | 
			
		||||
                  <input type="file" class="form-control" name="receipt_image" id="id_receipt_image" accept="image/*" required>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="d-flex justify-content-end">
 | 
			
		||||
                  <button type="button" id="btnAddFinalPayment" class="btn btn-primary">افزودن</button>
 | 
			
		||||
                </div>
 | 
			
		||||
              </form>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-12 col-lg-7">
 | 
			
		||||
          <div class="card mb-3 border">
 | 
			
		||||
            <div class="card-header"><h5 class="mb-0">وضعیت فاکتور</h5></div>
 | 
			
		||||
            <div class="card-body">
 | 
			
		||||
              <div class="row g-3">
 | 
			
		||||
                <div class="col-6">
 | 
			
		||||
                  <div class="border rounded p-3">
 | 
			
		||||
                    <div class="small text-muted">مبلغ نهایی</div>
 | 
			
		||||
                    <div class="h5 mt-1">{{ invoice.final_amount|floatformat:0|intcomma:False }} تومان</div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="col-6">
 | 
			
		||||
                  <div class="border rounded p-3">
 | 
			
		||||
                    <div class="small text-muted">مانده</div>
 | 
			
		||||
                    <div class="h5 mt-1 {% if invoice.remaining_amount <= 0 %}text-success{% else %}text-danger{% endif %}">{{ invoice.remaining_amount|floatformat:0|intcomma:False }} تومان</div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div class="card border">
 | 
			
		||||
            <div class="card-header"><h5 class="mb-0">تراکنشها</h5></div>
 | 
			
		||||
            <div class="table-responsive">
 | 
			
		||||
              <table class="table table-striped mb-0">
 | 
			
		||||
                <thead>
 | 
			
		||||
                  <tr>
 | 
			
		||||
                    <th>نوع</th>
 | 
			
		||||
                    <th>مبلغ</th>
 | 
			
		||||
                    <th>تاریخ</th>
 | 
			
		||||
                    <th>روش</th>
 | 
			
		||||
                    <th>شماره مرجع</th>
 | 
			
		||||
                    <th style="width:150px">عملیات</th>
 | 
			
		||||
                  </tr>
 | 
			
		||||
                </thead>
 | 
			
		||||
                <tbody>
 | 
			
		||||
                  {% for p in payments %}
 | 
			
		||||
                  <tr>
 | 
			
		||||
                    <td>{% if p.direction == 'in' %}<span class="badge bg-success">دریافتی{% else %}<span class="badge bg-warning text-dark">پرداختی{% endif %}</span></td>
 | 
			
		||||
                    <td>{{ p.amount|floatformat:0|intcomma:False }} تومان</td>
 | 
			
		||||
                    <td>{{ p.payment_date|to_jalali }}</td>
 | 
			
		||||
                    <td>{{ p.get_payment_method_display }}</td>
 | 
			
		||||
                    <td>{{ p.reference_number|default:'-' }}</td>
 | 
			
		||||
                    <td>
 | 
			
		||||
                      <div class="btn-group">
 | 
			
		||||
                        {% if p.receipt_image %}
 | 
			
		||||
                          <a href="{{ p.receipt_image.url }}" target="_blank" class="btn btn-sm btn-outline-secondary" title="مشاهده" aria-label="مشاهده">
 | 
			
		||||
                            <i class="bx bx-show"></i>
 | 
			
		||||
                          </a>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                        <button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteFinalPayment({{ p.id }})" title="حذف" aria-label="حذف"><i class="bx bx-trash"></i></button>
 | 
			
		||||
                      </div>
 | 
			
		||||
                    </td>
 | 
			
		||||
                  </tr>
 | 
			
		||||
                  {% empty %}
 | 
			
		||||
                  <tr><td colspan="6" class="text-center text-muted">تراکنشی ندارد</td></tr>
 | 
			
		||||
                  {% endfor %}
 | 
			
		||||
                </tbody>
 | 
			
		||||
              </table>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="card-footer d-flex justify-content-between">
 | 
			
		||||
              {% if previous_step %}
 | 
			
		||||
                <a href="{% url 'processes:step_detail' instance.id previous_step.id %}" class="btn btn-label-secondary">قبلی</a>
 | 
			
		||||
              {% else %}
 | 
			
		||||
                <span></span>
 | 
			
		||||
              {% endif %}
 | 
			
		||||
              <button type="button" id="btnApproveFinalSettlement" class="btn btn-primary">تایید و ادامه</button>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block script %}
 | 
			
		||||
<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 initPersianDatePicker(){
 | 
			
		||||
    if (window.$ && $.fn.persianDatepicker && $('#id_payment_date').length) {
 | 
			
		||||
      $('#id_payment_date').persianDatepicker({
 | 
			
		||||
        format: 'YYYY/MM/DD', initialValue: false, autoClose: true, persianDigit: false, observer: true,
 | 
			
		||||
        calendar: { persian: { locale: 'fa', leapYearMode: 'astronomical' } },
 | 
			
		||||
        onSelect: function(unix){
 | 
			
		||||
          const g = new window.persianDate(unix).toCalendar('gregorian').format('YYYY-MM-DD');
 | 
			
		||||
          $('#id_payment_date').attr('data-gregorian', g);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  })();
 | 
			
		||||
 | 
			
		||||
  function buildForm(){
 | 
			
		||||
    const fd = new FormData(document.getElementById('formFinalPayment'));
 | 
			
		||||
    const g = document.getElementById('id_payment_date').getAttribute('data-gregorian');
 | 
			
		||||
    if (g) { fd.set('payment_date', g); }
 | 
			
		||||
    return fd;
 | 
			
		||||
  }
 | 
			
		||||
  document.getElementById('btnAddFinalPayment').addEventListener('click', function(){
 | 
			
		||||
    const fd = buildForm();
 | 
			
		||||
    // Frontend validation
 | 
			
		||||
    const amount = document.getElementById('id_amount').value.trim();
 | 
			
		||||
    const payDate = document.getElementById('id_payment_date').value.trim();
 | 
			
		||||
    const method = document.getElementById('id_payment_method').value.trim();
 | 
			
		||||
    const ref = document.getElementById('id_reference_number').value.trim();
 | 
			
		||||
    const img = document.getElementById('id_receipt_image').files[0];
 | 
			
		||||
    const dir = document.getElementById('id_direction').value;
 | 
			
		||||
    if (!amount || !payDate || !method || !ref || !img) {
 | 
			
		||||
      showToast('همه فیلدها الزامی است', 'danger');
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    fetch('{% url "invoices:add_final_payment" instance.id step.id %}', { method:'POST', body: fd })
 | 
			
		||||
      .then(r=>r.json()).then(resp=>{
 | 
			
		||||
        if (resp.success) {
 | 
			
		||||
          showToast('تراکنش ثبت شد', 'success');
 | 
			
		||||
          if (resp.redirect) setTimeout(()=>{ window.location.href = resp.redirect; }, 700);
 | 
			
		||||
        } else {
 | 
			
		||||
          showToast(resp.message || 'خطا در ثبت تراکنش', 'danger');
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(()=> showToast('خطا در ارتباط با سرور', 'danger'));
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  function deleteFinalPayment(id){
 | 
			
		||||
    const fd = new FormData();
 | 
			
		||||
    fd.append('csrfmiddlewaretoken', document.querySelector('input[name=csrfmiddlewaretoken]').value);
 | 
			
		||||
    fetch(`{% url "invoices:delete_final_payment" instance.id step.id 0 %}`.replace('/0/', `/${id}/`), { method:'POST', body: fd })
 | 
			
		||||
      .then(r=>r.json()).then(resp=>{
 | 
			
		||||
        if (resp.success) {
 | 
			
		||||
          showToast('حذف شد', 'success');
 | 
			
		||||
          if (resp.redirect) setTimeout(()=>{ window.location.href = resp.redirect; }, 500);
 | 
			
		||||
        } else {
 | 
			
		||||
          showToast(resp.message || 'خطا در حذف', 'danger');
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(()=> showToast('خطا در ارتباط با سرور', 'danger'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  document.getElementById('btnApproveFinalSettlement').addEventListener('click', function(){
 | 
			
		||||
    const fd = new FormData();
 | 
			
		||||
    fd.append('csrfmiddlewaretoken', document.querySelector('input[name=csrfmiddlewaretoken]').value);
 | 
			
		||||
    fetch('{% url "invoices:approve_final_settlement" instance.id step.id %}', { method:'POST', body: fd })
 | 
			
		||||
      .then(r=>r.json()).then(resp=>{
 | 
			
		||||
        if (resp.success) {
 | 
			
		||||
          showToast(resp.message || 'تایید شد', 'success');
 | 
			
		||||
          if (resp.redirect) setTimeout(()=>{ window.location.href = resp.redirect; }, 600);
 | 
			
		||||
        } else {
 | 
			
		||||
          showToast(resp.message || 'خطا در تایید', 'danger');
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(()=> showToast('خطا در ارتباط با سرور', 'danger'));
 | 
			
		||||
  });
 | 
			
		||||
</script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -243,12 +243,12 @@
 | 
			
		|||
      body: fd
 | 
			
		||||
    }).then(r => r.json()).then(resp => {
 | 
			
		||||
      if (resp.success) {
 | 
			
		||||
        showToast('فیش با موفقیت ثبت شد', 'success');
 | 
			
		||||
        showToast(resp.message || 'فیش با موفقیت ثبت شد', 'success');
 | 
			
		||||
        if (resp.redirect) {
 | 
			
		||||
          setTimeout(() => { window.location.href = resp.redirect; }, 700);
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        showToast(resp.message || 'خطا در ثبت فیش', 'danger');
 | 
			
		||||
        showToast(resp.message + ':' + resp.error || 'خطا در ثبت فیش', 'danger');
 | 
			
		||||
      }
 | 
			
		||||
    }).catch(() => showToast('خطا در ارتباط با سرور', 'danger'));
 | 
			
		||||
  });
 | 
			
		||||
| 
						 | 
				
			
			@ -267,11 +267,13 @@
 | 
			
		|||
      method: 'POST',
 | 
			
		||||
      body: fd
 | 
			
		||||
    }).then(r => r.json()).then(resp => {
 | 
			
		||||
      if (resp.success && resp.redirect) {
 | 
			
		||||
        showToast('فیش با موفقیت حذف شد', 'success');
 | 
			
		||||
        setTimeout(() => { window.location.href = resp.redirect; }, 700);
 | 
			
		||||
      if (resp.success) {
 | 
			
		||||
        showToast(resp.message || 'فیش با موفقیت حذف شد', 'success');
 | 
			
		||||
        if (resp.redirect) {
 | 
			
		||||
          setTimeout(() => { window.location.href = resp.redirect; }, 700);
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        showToast(resp.message || 'خطا در حذف فیش', 'danger');
 | 
			
		||||
        showToast(resp.message || resp.error || 'خطا در حذف فیش', 'danger');
 | 
			
		||||
      }
 | 
			
		||||
    }).catch(() => showToast('خطا در ارتباط با سرور', 'danger'));
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -288,11 +290,13 @@
 | 
			
		|||
      method: 'POST',
 | 
			
		||||
      body: fd
 | 
			
		||||
    }).then(r => r.json()).then(resp => {
 | 
			
		||||
      if (resp.success && resp.redirect) {
 | 
			
		||||
        showToast(resp.message, 'success');
 | 
			
		||||
        setTimeout(() => { window.location.href = resp.redirect; }, 600);
 | 
			
		||||
      if (resp.success) {
 | 
			
		||||
        showToast(resp.message || 'پرداختها تایید شد', 'success');
 | 
			
		||||
        if (resp.redirect) {
 | 
			
		||||
          setTimeout(() => { window.location.href = resp.redirect; }, 600);
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        showToast(resp.message || 'خطا در تایید پرداختها', 'danger');
 | 
			
		||||
        showToast(resp.message || resp.error || 'خطا در تایید پرداختها', 'danger');
 | 
			
		||||
      }
 | 
			
		||||
    }).catch(() => showToast('خطا در ارتباط با سرور', 'danger'));
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@
 | 
			
		|||
        {% stepper_header instance step %}
 | 
			
		||||
        <div class="bs-stepper-content">
 | 
			
		||||
            <!-- Invoice Preview Card -->
 | 
			
		||||
      <div class="card invoice-preview-card mt-4">
 | 
			
		||||
      <div class="card invoice-preview-card mt-4 border">
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <div class="d-flex justify-content-between flex-xl-row flex-md-column flex-sm-row flex-column p-sm-3 p-0">
 | 
			
		||||
            <div class="mb-xl-0 mb-4">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue