shafafiyat/certificates/views.py

141 lines
6.3 KiB
Python

from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import JsonResponse
from django.urls import reverse
from django.utils import timezone
from processes.models import ProcessInstance, StepInstance
from invoices.models import Invoice
from installations.models import InstallationReport
from .models import CertificateTemplate, CertificateInstance
from common.consts import UserRoles
from _helpers.jalali import Gregorian
from processes.utils import get_scoped_instance_or_404
def _to_jalali(date_obj):
try:
g = Gregorian(date_obj)
y, m, d = g.persian_tuple()
return f"{y}/{m:02d}/{d:02d}"
except Exception:
return ''
def _render_template(template: CertificateTemplate, instance: ProcessInstance):
well = instance.well
rep = instance.representative
latest_report = InstallationReport.objects.filter(assignment__process_instance=instance).order_by('-created').first()
ctx = {
'today_jalali': _to_jalali(timezone.now().date()),
'request_code': instance.code,
'company_name': (template.company.name if template.company else '') or '',
'customer_full_name': rep.get_full_name() if rep else '',
'water_subscription_number': getattr(well, 'water_subscription_number', '') or '',
'address': getattr(well, 'county', '') or '',
'visit_date_jalali': _to_jalali(getattr(latest_report, 'visited_date', None)) if latest_report else '',
}
title = (template.title or '').format(**ctx)
body = (template.body or '')
# Render body placeholders with bold values
for k, v in ctx.items():
body = body.replace(f"{{{{ {k} }}}}", f"<strong>{str(v)}</strong>")
return title, body
@login_required
def certificate_step(request, instance_id, step_id):
instance = get_scoped_instance_or_404(request, instance_id)
step = get_object_or_404(instance.process.steps, id=step_id)
# Ensure all previous steps are completed and invoice settled
prior_steps = instance.process.steps.filter(order__lt=instance.current_step.order if instance.current_step else 9999)
incomplete = StepInstance.objects.filter(process_instance=instance, step__in=prior_steps).exclude(status='completed').exists()
if incomplete:
messages.error(request, 'ابتدا همه مراحل قبلی را تکمیل کنید')
return redirect('processes:request_list')
inv = Invoice.objects.filter(process_instance=instance).first()
if inv:
inv.calculate_totals()
if inv.remaining_amount != 0:
messages.error(request, 'مانده فاکتور باید صفر باشد')
return redirect('processes:request_list')
template = CertificateTemplate.objects.filter(is_active=True).order_by('-created').first()
if not template:
return render(request, 'certificates/missing.html', {})
title, body = _render_template(template, instance)
cert, _ = CertificateInstance.objects.get_or_create(
process_instance=instance,
defaults={'template': template, 'rendered_title': title, 'rendered_body': body}
)
# keep rendered up-to-date
cert.template = template
cert.rendered_title = title
cert.rendered_body = body
cert.save()
previous_step = instance.process.steps.filter(order__lt=instance.current_step.order).last() if instance.current_step else None
next_step = instance.process.steps.filter(order__gt=instance.current_step.order).first() if instance.current_step else None
if request.method == 'POST':
# Only broker can approve and finish certificate step
try:
if not (hasattr(request.user, 'profile') and request.user.profile.has_role(UserRoles.BROKER)):
messages.error(request, 'شما مجوز تایید این مرحله را ندارید')
return redirect('processes:step_detail', instance_id=instance.id, step_id=step.id)
except Exception:
messages.error(request, 'شما مجوز تایید این مرحله را ندارید')
return redirect('processes:step_detail', instance_id=instance.id, step_id=step.id)
# Safety check: ensure ALL previous steps are completed before approval
try:
prev_steps_qs = instance.process.steps.filter(order__lt=step.order)
has_incomplete = StepInstance.objects.filter(process_instance=instance, step__in=prev_steps_qs).exclude(status='completed').exists()
if has_incomplete:
messages.error(request, 'ابتدا همه مراحل قبلی را تکمیل کنید')
return redirect('processes:step_detail', instance_id=instance.id, step_id=step.id)
except Exception:
messages.error(request, 'خطا در بررسی مراحل قبلی')
return redirect('processes:step_detail', instance_id=instance.id, step_id=step.id)
cert.approved = True
cert.approved_at = timezone.now()
cert.save()
step_instance, _ = StepInstance.objects.get_or_create(process_instance=instance, step_id=step_id)
step_instance.status = 'completed'
step_instance.completed_at = timezone.now()
step_instance.save()
if next_step:
instance.current_step = next_step
instance.save()
return redirect('processes:step_detail', instance_id=instance.id, step_id=next_step.id)
# Mark the whole process instance as completed on the last step
instance.status = 'completed'
instance.save()
return redirect('processes:instance_summary', instance_id=instance.id)
return render(request, 'certificates/step.html', {
'instance': instance,
'template': template,
'cert': cert,
'previous_step': previous_step,
'next_step': next_step,
'step': step,
})
@login_required
def certificate_print(request, instance_id):
instance = get_scoped_instance_or_404(request, instance_id)
cert = CertificateInstance.objects.filter(process_instance=instance).order_by('-created').first()
template = cert.template if cert else None
return render(request, 'certificates/print.html', {
'instance': instance,
'cert': cert,
'template': template,
})