from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required from django.urls import reverse from django.utils import timezone from decimal import Decimal from django.template import Template, Context from django.utils.safestring import mark_safe from processes.models import ProcessInstance, StepInstance from common.consts import UserRoles from .models import ContractTemplate, ContractInstance from invoices.models import Invoice, Quote from _helpers.utils import jalali_converter2 from django.http import JsonResponse from processes.utils import get_scoped_instance_or_404 def build_contract_context(instance: ProcessInstance) -> dict: representative = instance.representative profile = getattr(representative, 'profile', None) well = instance.well # Compute prepayment from Quote-linked invoice payments quote = Quote.objects.filter(process_instance=instance).first() invoice = Invoice.objects.filter(quote=quote).first() if quote else None payments_qs = invoice.payments.filter(is_deleted=False, direction='in').all() if invoice else [] total_paid = sum((p.amount for p in payments_qs), Decimal('0')) try: latest_payment_date = max((p.payment_date for p in payments_qs)) if payments_qs else None except Exception: latest_payment_date = None return { 'customer_full_name': mark_safe(f"{representative.get_full_name() if representative else ''}"), 'registration_number': mark_safe(f"{instance.broker.company.registration_number if instance.broker and instance.broker.company else ''}"), 'national_code': mark_safe(f"{profile.national_code if profile else ''}"), 'address': mark_safe(f"{profile.address if profile else ''}"), 'phone': mark_safe(f"{profile.phone_number_1 if profile else ''}"), 'phone2': mark_safe(f"{profile.phone_number_2 if profile else ''}"), 'water_subscription_number': mark_safe(f"{well.water_subscription_number if well else ''}"), 'electricity_subscription_number': mark_safe(f"{well.electricity_subscription_number if well else ''}"), 'water_meter_serial_number': mark_safe(f"{well.water_meter_serial_number if well else ''}"), 'well_power': mark_safe(f"{well.well_power if well else ''}"), 'request_code': mark_safe(f"{instance.code}"), 'today': mark_safe(f"{jalali_converter2(timezone.now())}"), 'company_name': mark_safe(f"{instance.broker.company.name if instance.broker and instance.broker.company else ''}"), 'city_name': mark_safe(f"{instance.broker.affairs.county.city.name if instance.broker and instance.broker.affairs and instance.broker.affairs.county and instance.broker.affairs.county.city else ''}"), 'card_number': mark_safe(f"{instance.representative.profile.card_number if instance.representative else ''}"), 'account_number': mark_safe(f"{instance.representative.profile.account_number if instance.representative else ''}"), 'bank_name': mark_safe(f"{instance.representative.profile.get_bank_name_display() if instance.representative else ''}"), 'prepayment_amount': mark_safe(f"{int(total_paid):,}"), 'prepayment_date': mark_safe(f"{jalali_converter2(latest_payment_date)}") if latest_payment_date else '', } @login_required def contract_step(request, instance_id, step_id): instance = get_scoped_instance_or_404(request, instance_id) # Resolve step navigation step = get_object_or_404(instance.process.steps, id=step_id) previous_step = instance.process.steps.filter(order__lt=step.order).last() next_step = instance.process.steps.filter(order__gt=step.order).first() profile = getattr(request.user, 'profile', None) is_broker = False can_view_contract_body = True try: is_broker = bool(profile and profile.has_role(UserRoles.BROKER)) if profile and profile.has_role(UserRoles.INSTALLER): can_view_contract_body = False except Exception: pass template_obj = ContractTemplate.objects.first() if not template_obj: return render(request, 'contracts/contract_missing.html', {'instance': instance}) ctx = build_contract_context(instance) rendered = Template(template_obj.body).render(Context(ctx)) contract, _ = ContractInstance.objects.get_or_create( process_instance=instance, defaults={ 'template': template_obj, 'rendered_body': rendered, 'created_by': request.user, } ) # keep latest rendering if template changed (optional) contract.template = template_obj contract.rendered_body = rendered contract.save() # If user submits to go next, only broker can complete and go to next if request.method == 'POST': if not is_broker: return JsonResponse({'success': False, 'message': 'شما مجوز تایید این مرحله را ندارید'}, status=403) StepInstance.objects.update_or_create( process_instance=instance, step=step, defaults={'status': 'completed', 'completed_at': timezone.now()} ) if next_step: instance.current_step = next_step instance.save() return redirect('processes:step_detail', instance_id=instance.id, step_id=next_step.id) return redirect('processes:request_list') return render(request, 'contracts/contract_step.html', { 'instance': instance, 'step': step, 'contract': contract, 'template': template_obj, 'previous_step': previous_step, 'next_step': next_step, 'is_broker': is_broker, 'can_view_contract_body': can_view_contract_body, }) @login_required def contract_print(request, instance_id): instance = get_scoped_instance_or_404(request, instance_id) contract = get_object_or_404(ContractInstance, process_instance=instance) return render(request, 'contracts/contract_print.html', { 'instance': instance, 'contract': contract, })