fix final payment step.
This commit is contained in:
parent
93db2fe7f5
commit
9592c00565
6 changed files with 305 additions and 80 deletions
|
@ -12,7 +12,7 @@ import json
|
|||
from processes.models import ProcessInstance, ProcessStep, StepInstance, StepRejection, StepApproval
|
||||
from accounts.models import Role
|
||||
from common.consts import UserRoles
|
||||
from .models import Item, Quote, QuoteItem, Payment, Invoice
|
||||
from .models import Item, Quote, QuoteItem, Payment, Invoice, InvoiceItem
|
||||
from installations.models import InstallationReport, InstallationItemChange
|
||||
|
||||
|
||||
|
@ -792,14 +792,7 @@ def approve_final_invoice(request, instance_id, step_id):
|
|||
return JsonResponse({'success': False, 'message': 'شما مجوز تایید این مرحله را ندارید'}, status=403)
|
||||
except Exception:
|
||||
return JsonResponse({'success': False, 'message': 'شما مجوز تایید این مرحله را ندارید'}, status=403)
|
||||
# Block approval when there is any remaining (positive or negative)
|
||||
invoice.calculate_totals()
|
||||
# if invoice.remaining_amount != 0:
|
||||
# return JsonResponse({
|
||||
# 'success': False,
|
||||
# 'message': f"تا زمانی که مانده فاکتور صفر نشده امکان تایید نیست (مانده فعلی: {invoice.remaining_amount})"
|
||||
# })
|
||||
# mark step completed
|
||||
|
||||
step_instance, _ = StepInstance.objects.get_or_create(process_instance=instance, step=step)
|
||||
step_instance.status = 'completed'
|
||||
step_instance.completed_at = timezone.now()
|
||||
|
@ -826,7 +819,7 @@ def add_special_charge(request, instance_id, step_id):
|
|||
return JsonResponse({'success': False, 'message': 'شما مجوز افزودن هزینه ویژه را ندارید'}, status=403)
|
||||
except Exception:
|
||||
return JsonResponse({'success': False, 'message': 'شما مجوز افزودن هزینه ویژه را ندارید'}, status=403)
|
||||
# charge_type was removed from UI; we no longer require it
|
||||
|
||||
item_id = request.POST.get('item_id')
|
||||
amount = (request.POST.get('amount') or '').strip()
|
||||
if not item_id:
|
||||
|
@ -841,7 +834,7 @@ def add_special_charge(request, instance_id, step_id):
|
|||
# Fetch existing special item from DB
|
||||
special_item = get_object_or_404(Item, id=item_id, is_special=True)
|
||||
|
||||
from .models import InvoiceItem
|
||||
|
||||
InvoiceItem.objects.create(
|
||||
invoice=invoice,
|
||||
item=special_item,
|
||||
|
@ -863,7 +856,6 @@ def delete_special_charge(request, instance_id, step_id, item_id):
|
|||
return JsonResponse({'success': False, 'message': 'شما مجوز حذف هزینه ویژه را ندارید'}, status=403)
|
||||
except Exception:
|
||||
return JsonResponse({'success': False, 'message': 'شما مجوز حذف هزینه ویژه را ندارید'}, status=403)
|
||||
from .models import InvoiceItem
|
||||
inv_item = get_object_or_404(InvoiceItem, id=item_id, invoice=invoice)
|
||||
# allow deletion only for special items
|
||||
try:
|
||||
|
@ -880,6 +872,7 @@ def delete_special_charge(request, instance_id, step_id, item_id):
|
|||
def final_settlement_step(request, instance_id, step_id):
|
||||
instance = get_object_or_404(ProcessInstance, id=instance_id)
|
||||
step = get_object_or_404(instance.process.steps, id=step_id)
|
||||
|
||||
if not instance.can_access_step(step):
|
||||
messages.error(request, 'شما به این مرحله دسترسی ندارید. ابتدا مراحل قبلی را تکمیل کنید.')
|
||||
return redirect('processes:request_list')
|
||||
|
@ -890,6 +883,7 @@ def final_settlement_step(request, instance_id, step_id):
|
|||
|
||||
# Ensure step instance exists
|
||||
step_instance, _ = StepInstance.objects.get_or_create(process_instance=instance, step=step, defaults={'status': 'in_progress'})
|
||||
|
||||
# Build approver statuses for template
|
||||
reqs = list(step.approver_requirements.select_related('role').all())
|
||||
approvals_map = {a.role_id: a.decision for a in step_instance.approvals.select_related('role').all()}
|
||||
|
@ -947,6 +941,13 @@ def final_settlement_step(request, instance_id, step_id):
|
|||
defaults={'approved_by': request.user, 'decision': 'rejected', 'reason': reason}
|
||||
)
|
||||
StepRejection.objects.create(step_instance=step_instance, rejected_by=request.user, reason=reason)
|
||||
# If current step is ahead of this step, reset it back to this step (align behavior with other steps)
|
||||
try:
|
||||
if instance.current_step and instance.current_step.order > step.order:
|
||||
instance.current_step = step
|
||||
instance.save(update_fields=['current_step'])
|
||||
except Exception:
|
||||
pass
|
||||
messages.success(request, 'مرحله تسویه نهایی رد شد و برای اصلاح بازگشت.')
|
||||
return redirect('invoices:final_settlement_step', instance_id=instance.id, step_id=step.id)
|
||||
|
||||
|
@ -984,6 +985,7 @@ def add_final_payment(request, instance_id, step_id):
|
|||
return JsonResponse({'success': False, 'message': 'شما مجوز افزودن تراکنش تسویه را ندارید'}, status=403)
|
||||
except Exception:
|
||||
return JsonResponse({'success': False, 'message': 'شما مجوز افزودن تراکنش تسویه را ندارید'}, status=403)
|
||||
|
||||
amount = (request.POST.get('amount') or '').strip()
|
||||
payment_date = (request.POST.get('payment_date') or '').strip()
|
||||
payment_method = (request.POST.get('payment_method') or '').strip()
|
||||
|
@ -1038,12 +1040,14 @@ def add_final_payment(request, instance_id, step_id):
|
|||
)
|
||||
# After creation, totals auto-updated by model save. Respond with redirect and new totals for UX.
|
||||
invoice.refresh_from_db()
|
||||
# After payment change, set step back to in_progress
|
||||
|
||||
# On delete, return to awaiting approval
|
||||
try:
|
||||
si, _ = StepInstance.objects.get_or_create(process_instance=instance, step=step)
|
||||
si.status = 'in_progress'
|
||||
si.completed_at = None
|
||||
si.save()
|
||||
si.approvals.all().delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
@ -1065,6 +1069,16 @@ def add_final_payment(request, instance_id, step_id):
|
|||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# If current step is ahead of this step, reset it back to this step
|
||||
try:
|
||||
if instance.current_step and instance.current_step.order > step.order:
|
||||
instance.current_step = step
|
||||
instance.save(update_fields=['current_step'])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'redirect': reverse('invoices:final_settlement_step', args=[instance.id, step_id]),
|
||||
|
@ -1091,14 +1105,44 @@ def delete_final_payment(request, instance_id, step_id, payment_id):
|
|||
return JsonResponse({'success': False, 'message': 'شما مجوز حذف تراکنش تسویه را ندارید'}, status=403)
|
||||
payment.delete()
|
||||
invoice.refresh_from_db()
|
||||
# After payment change, set step back to in_progress
|
||||
|
||||
# On delete, return to awaiting approval
|
||||
try:
|
||||
si, _ = StepInstance.objects.get_or_create(process_instance=instance, step=step)
|
||||
si.status = 'in_progress'
|
||||
si.completed_at = None
|
||||
si.save()
|
||||
si.approvals.all().delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Reset ALL subsequent completed steps to in_progress
|
||||
try:
|
||||
subsequent_steps = instance.process.steps.filter(order__gt=step.order)
|
||||
for subsequent_step in subsequent_steps:
|
||||
subsequent_step_instance = instance.step_instances.filter(step=subsequent_step).first()
|
||||
if subsequent_step_instance and subsequent_step_instance.status == 'completed':
|
||||
# Bypass validation by using update() instead of save()
|
||||
instance.step_instances.filter(step=subsequent_step).update(
|
||||
status='in_progress',
|
||||
completed_at=None
|
||||
)
|
||||
# Clear previous approvals if the step requires re-approval
|
||||
try:
|
||||
subsequent_step_instance.approvals.all().delete()
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# If current step is ahead of this step, reset it back to this step
|
||||
try:
|
||||
if instance.current_step and instance.current_step.order > step.order:
|
||||
instance.current_step = step
|
||||
instance.save(update_fields=['current_step'])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return JsonResponse({'success': True, 'redirect': reverse('invoices:final_settlement_step', args=[instance.id, step_id]), 'totals': {
|
||||
'final_amount': str(invoice.final_amount),
|
||||
'paid_amount': str(invoice.paid_amount),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue