635 lines
23 KiB
Python
635 lines
23 KiB
Python
import csv
|
|
import io
|
|
from django.shortcuts import render, redirect, get_object_or_404
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.contrib.auth import login, authenticate, logout
|
|
from django.contrib import messages
|
|
from django.db.models import Sum, Count, F
|
|
from django.utils import timezone
|
|
from datetime import date
|
|
from django.http import JsonResponse, HttpResponse
|
|
import json
|
|
import os
|
|
|
|
from .models import Expense, Project, Category, SystemSetting, UserProfile, AuditLog, ApprovalStatusEnum, CurrencyEnum, Vendor, Document
|
|
from .forms import ExpenseForm, ProjectForm, SystemSettingForm, ResponsableForm, CategoryForm, VendorForm
|
|
from .decorators import role_required
|
|
from django.contrib.auth.models import User, Group
|
|
from .chile_regions import REGIONS_COMMUNES
|
|
|
|
def login_view(request):
|
|
if request.user.is_authenticated:
|
|
return redirect('dashboard')
|
|
if request.method == 'POST':
|
|
username = request.POST.get('username')
|
|
password = request.POST.get('password')
|
|
user = authenticate(request, username=username, password=password)
|
|
if user is not None:
|
|
login(request, user)
|
|
return redirect('dashboard')
|
|
else:
|
|
messages.error(request, 'Usuario o contraseña incorrectos.')
|
|
return render(request, 'registration/login.html')
|
|
|
|
def logout_view(request):
|
|
logout(request)
|
|
return redirect('login')
|
|
|
|
|
|
@login_required
|
|
def dashboard(request):
|
|
today = date.today()
|
|
first_day_of_month = today.replace(day=1)
|
|
|
|
total_month_clp = Expense.objects.filter(
|
|
date__gte=first_day_of_month
|
|
).aggregate(total=Sum('amount_clp'))['total'] or 0
|
|
|
|
total_all_clp = Expense.objects.aggregate(
|
|
total=Sum('amount_clp')
|
|
)['total'] or 0
|
|
|
|
project_count = Project.objects.count()
|
|
today_count = Expense.objects.filter(date=today).count()
|
|
|
|
recent_expenses = Expense.objects.select_related(
|
|
'project', 'category', 'user', 'responsible_person'
|
|
).order_by('-date')[:10]
|
|
|
|
# Presupuesto Global
|
|
setting, _ = SystemSetting.objects.get_or_create(id=1)
|
|
global_budget = setting.global_budget
|
|
remaining_budget = global_budget - total_all_clp
|
|
|
|
# Chart Data: Gastos por Categoría
|
|
cat_expenses = Expense.objects.values('category__name').annotate(total=Sum('amount_clp')).order_by('-total')
|
|
category_labels = [item['category__name'] or 'Sin Categoría' for item in cat_expenses]
|
|
category_data = [float(item['total'] or 0) for item in cat_expenses]
|
|
|
|
# Chart Data: Gastos por Proyecto
|
|
proj_expenses = Expense.objects.values('project__name').annotate(total=Sum('amount_clp')).order_by('-total')
|
|
project_labels = [item['project__name'] or 'Sin Proyecto' for item in proj_expenses]
|
|
project_data = [float(item['total'] or 0) for item in proj_expenses]
|
|
|
|
context = {
|
|
'total_month': total_month_clp,
|
|
'total_all': total_all_clp,
|
|
'project_count': project_count,
|
|
'today_count': today_count,
|
|
'recent_expenses': recent_expenses,
|
|
'global_budget': global_budget,
|
|
'remaining_budget': remaining_budget,
|
|
'category_labels_json': json.dumps(category_labels),
|
|
'category_data_json': json.dumps(category_data),
|
|
'project_labels_json': json.dumps(project_labels),
|
|
'project_data_json': json.dumps(project_data),
|
|
}
|
|
return render(request, 'expenses/dashboard.html', context)
|
|
|
|
|
|
@login_required
|
|
def expense_list(request):
|
|
expenses = Expense.objects.select_related('project', 'category', 'user').order_by('-date')
|
|
|
|
# Filtros
|
|
project_id = request.GET.get('project')
|
|
category_id = request.GET.get('category')
|
|
|
|
if project_id:
|
|
expenses = expenses.filter(project_id=project_id)
|
|
if category_id:
|
|
expenses = expenses.filter(category_id=category_id)
|
|
|
|
context = {
|
|
'expenses': expenses,
|
|
'projects': Project.objects.all(),
|
|
'categories': Category.objects.all(),
|
|
'selected_project': project_id,
|
|
'selected_category': category_id,
|
|
}
|
|
return render(request, 'expenses/expense_list.html', context)
|
|
|
|
|
|
@login_required
|
|
def expense_create(request):
|
|
# Only allow creation if user is admin or allowed to
|
|
if request.method == 'POST':
|
|
form = ExpenseForm(request.POST, request.FILES)
|
|
if form.is_valid():
|
|
expense = form.save(commit=False)
|
|
expense.user = request.user
|
|
# Auto convert to USD if CLP
|
|
setting, _ = SystemSetting.objects.get_or_create(id=1)
|
|
if expense.currency == CurrencyEnum.CLP:
|
|
expense.amount_usd = expense.amount_clp / setting.usd_exchange_rate
|
|
else:
|
|
expense.amount_usd = expense.amount_clp
|
|
expense.amount_clp = expense.amount_usd * setting.usd_exchange_rate
|
|
|
|
expense.save()
|
|
|
|
receipts = request.FILES.getlist('receipt')
|
|
if receipts:
|
|
from .models import Document
|
|
for f in receipts:
|
|
Document.objects.create(expense=expense, file=f, title=f.name, uploaded_by=request.user)
|
|
|
|
AuditLog.objects.create(
|
|
user=request.user,
|
|
action="Gasto Creado",
|
|
entity_name="Expense",
|
|
entity_id=expense.expense_code,
|
|
description=f"Se creó el gasto por {expense.amount_clp} CLP"
|
|
)
|
|
messages.success(request, 'Gasto registrado exitosamente.')
|
|
return redirect('expense_list')
|
|
else:
|
|
form = ExpenseForm()
|
|
|
|
context = {
|
|
'form': form,
|
|
'regions_communes_json': json.dumps(REGIONS_COMMUNES)
|
|
}
|
|
return render(request, 'expenses/expense_form.html', context)
|
|
|
|
|
|
@login_required
|
|
def expense_edit(request, pk):
|
|
expense = get_object_or_404(Expense, pk=pk)
|
|
user_groups = request.user.groups.values_list('name', flat=True)
|
|
if not (request.user.is_superuser or 'Administrador' in user_groups or expense.user == request.user):
|
|
messages.error(request, 'No tienes permisos para editar este gasto.')
|
|
return redirect('expense_list')
|
|
|
|
if expense.approval_status in [ApprovalStatusEnum.SOLICITADO_FINANZAS, ApprovalStatusEnum.LIBERADO_PAGADO]:
|
|
messages.error(request, 'Gasto bloqueado. No puedes editar un comprobante que ya está en finanzas o pagado.')
|
|
return redirect('expense_list')
|
|
|
|
old_amount = expense.amount_clp
|
|
|
|
if request.method == 'POST':
|
|
form = ExpenseForm(request.POST, request.FILES, instance=expense)
|
|
if form.is_valid():
|
|
exp = form.save(commit=False)
|
|
setting, _ = SystemSetting.objects.get_or_create(id=1)
|
|
exp.amount_usd = exp.amount_clp / setting.usd_exchange_rate
|
|
|
|
# Reset status if it was rejected
|
|
if exp.approval_status == ApprovalStatusEnum.OBSERVADO_RECHAZADO:
|
|
exp.approval_status = ApprovalStatusEnum.EN_REVISION
|
|
|
|
exp.save()
|
|
|
|
receipts = request.FILES.getlist('receipt')
|
|
if receipts:
|
|
from .models import Document
|
|
for f in receipts:
|
|
Document.objects.create(expense=exp, file=f, title=f.name, uploaded_by=request.user)
|
|
|
|
AuditLog.objects.create(
|
|
user=request.user,
|
|
action="Gasto Editado",
|
|
entity_name="Expense",
|
|
entity_id=exp.expense_code,
|
|
field_changed="amount_clp",
|
|
old_value=str(old_amount),
|
|
new_value=str(exp.amount_clp),
|
|
description=f"Se editó el monto del gasto"
|
|
)
|
|
messages.success(request, 'Gasto actualizado exitosamente.')
|
|
return redirect('expense_list')
|
|
else:
|
|
form = ExpenseForm(instance=expense)
|
|
|
|
context = {
|
|
'form': form,
|
|
'regions_communes_json': json.dumps(REGIONS_COMMUNES)
|
|
}
|
|
return render(request, 'expenses/expense_form.html', context)
|
|
|
|
|
|
@login_required
|
|
def expense_delete(request, pk):
|
|
expense = get_object_or_404(Expense, pk=pk)
|
|
user_groups = request.user.groups.values_list('name', flat=True)
|
|
if not (request.user.is_superuser or 'Administrador' in user_groups):
|
|
messages.error(request, 'Solo administradores pueden eliminar gastos.')
|
|
return redirect('expense_list')
|
|
|
|
if expense.approval_status in [ApprovalStatusEnum.SOLICITADO_FINANZAS, ApprovalStatusEnum.LIBERADO_PAGADO]:
|
|
messages.error(request, 'Gasto bloqueado. No puedes eliminar un comprobante que ya está en finanzas o pagado.')
|
|
return redirect('expense_list')
|
|
|
|
if request.method == 'POST':
|
|
code = expense.expense_code
|
|
expense.delete()
|
|
AuditLog.objects.create(
|
|
user=request.user,
|
|
action="Gasto Eliminado",
|
|
entity_name="Expense",
|
|
entity_id=code,
|
|
description="Se eliminó el gasto de la base de datos"
|
|
)
|
|
messages.success(request, 'Gasto eliminado.')
|
|
return redirect('expense_list')
|
|
|
|
|
|
# Flujo de 3 pasos
|
|
@login_required
|
|
def approve_expense(request, pk, action):
|
|
expense = get_object_or_404(Expense, pk=pk)
|
|
user_groups = request.user.groups.values_list('name', flat=True)
|
|
is_admin = request.user.is_superuser or 'Administrador' in user_groups
|
|
is_finanzas = 'Administrador Finanzas' in user_groups or is_admin
|
|
|
|
if action == 'solicitar':
|
|
# Step 1 -> 2
|
|
if not is_admin and expense.project.manager != request.user:
|
|
messages.error(request, "Solo el Administrador o el Encargado del Proyecto pueden solicitar pago a finanzas.")
|
|
return redirect('expense_list')
|
|
|
|
expense.approval_status = ApprovalStatusEnum.SOLICITADO_FINANZAS
|
|
expense.elevated_by = request.user
|
|
expense.save()
|
|
AuditLog.objects.create(
|
|
user=request.user,
|
|
action="ELEVATE_REQUEST",
|
|
entity_name="Expense",
|
|
entity_id=expense.expense_code,
|
|
description="Solicitud elevada a finanzas"
|
|
)
|
|
messages.success(request, "Solicitud elevada a finanzas.")
|
|
|
|
elif action == 'pagar':
|
|
# Step 2 -> 3
|
|
if not is_finanzas:
|
|
messages.error(request, "Solo Finanzas puede liberar el pago.")
|
|
return redirect('dashboard')
|
|
|
|
expense.approval_status = ApprovalStatusEnum.LIBERADO_PAGADO
|
|
expense.paid_by = request.user
|
|
expense.paid_at = timezone.now()
|
|
expense.save()
|
|
|
|
# Update Project Cost
|
|
proj = expense.project
|
|
if expense.tax_type == TaxTypeEnum.IVA_19:
|
|
proj.actual_cost_clp = proj.actual_cost_clp + expense.amount_clp
|
|
else:
|
|
proj.actual_cost_clp = proj.actual_cost_clp + expense.total_amount_clp
|
|
proj.save()
|
|
|
|
AuditLog.objects.create(
|
|
user=request.user,
|
|
action="APPROVE_PAYMENT",
|
|
entity_name="Expense",
|
|
entity_id=expense.expense_code,
|
|
description="Pago liberado"
|
|
)
|
|
messages.success(request, "Pago liberado con éxito.")
|
|
|
|
elif action == 'rechazar':
|
|
expense.approval_status = ApprovalStatusEnum.OBSERVADO_RECHAZADO
|
|
expense.save()
|
|
AuditLog.objects.create(
|
|
user=request.user,
|
|
action="REJECT",
|
|
entity_name="Expense",
|
|
entity_id=expense.expense_code,
|
|
description="Gasto observado/rechazado"
|
|
)
|
|
messages.warning(request, "Gasto rechazado.")
|
|
|
|
return redirect(request.META.get('HTTP_REFERER', 'dashboard'))
|
|
|
|
|
|
@login_required
|
|
def export_expenses_csv(request):
|
|
response = HttpResponse(content_type='text/csv')
|
|
response['Content-Disposition'] = f'attachment; filename="Gastos_EFINTEL_{date.today()}.csv"'
|
|
|
|
writer = csv.writer(response, delimiter=';')
|
|
writer.writerow([
|
|
'ID_Gasto', 'Codigo_Transaccion', 'Fecha', 'Proyecto_Codigo', 'Proyecto_Nombre',
|
|
'Monto_CLP', 'Monto_USD', 'Moneda_Original', 'Estado_Aprobacion',
|
|
'Responsable', 'Detalle', 'Region', 'Comuna', 'Proveedor'
|
|
])
|
|
|
|
expenses = Expense.objects.all().select_related('project', 'responsible_person')
|
|
for exp in expenses:
|
|
writer.writerow([
|
|
exp.id,
|
|
exp.expense_code,
|
|
exp.date,
|
|
exp.project.code,
|
|
exp.project.name,
|
|
exp.amount_clp,
|
|
exp.amount_usd,
|
|
exp.currency,
|
|
exp.get_approval_status_display(),
|
|
exp.responsible_person.username if exp.responsible_person else '',
|
|
exp.description,
|
|
exp.region,
|
|
exp.comuna,
|
|
exp.vendor
|
|
])
|
|
|
|
AuditLog.objects.create(
|
|
user=request.user,
|
|
action="EXPORT_CSV",
|
|
description="Se descargó la matriz de gastos en formato CSV."
|
|
)
|
|
|
|
return response
|
|
|
|
|
|
@login_required
|
|
def project_list(request):
|
|
projects = Project.objects.annotate(
|
|
expense_count=Count('expenses'),
|
|
total_expenses=Sum('expenses__amount_clp')
|
|
).select_related('manager')
|
|
|
|
context = {
|
|
'projects': projects,
|
|
}
|
|
return render(request, 'expenses/project_list.html', context)
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def gestion_panel(request):
|
|
projects = Project.objects.all().select_related('manager', 'created_by', 'parent', 'category')
|
|
categories = Category.objects.all().select_related('parent')
|
|
vendors = Vendor.objects.all()
|
|
responsables = User.objects.all().select_related('profile').prefetch_related('groups', 'profile__specialties')
|
|
settings_obj, _ = SystemSetting.objects.get_or_create(id=1)
|
|
logs = AuditLog.objects.all().select_related('user')[:100]
|
|
|
|
context = {
|
|
'projects': projects,
|
|
'categories': categories,
|
|
'vendors': vendors,
|
|
'responsables': responsables,
|
|
'settings': settings_obj,
|
|
'logs': logs,
|
|
}
|
|
return render(request, 'expenses/gestion.html', context)
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def settings_edit(request):
|
|
setting, _ = SystemSetting.objects.get_or_create(id=1)
|
|
if request.method == 'POST':
|
|
form = SystemSettingForm(request.POST, instance=setting)
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, 'Configuración actualizada.')
|
|
return redirect('gestion_panel')
|
|
else:
|
|
form = SystemSettingForm(instance=setting)
|
|
return render(request, 'expenses/settings_form.html', {'form': form})
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def project_create(request):
|
|
if request.method == 'POST':
|
|
form = ProjectForm(request.POST)
|
|
if form.is_valid():
|
|
project = form.save(commit=False)
|
|
project.created_by = request.user
|
|
project.save()
|
|
messages.success(request, 'Proyecto creado exitosamente.')
|
|
return redirect('gestion_panel')
|
|
else:
|
|
form = ProjectForm()
|
|
return render(request, 'expenses/project_form.html', {'form': form})
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def project_edit(request, pk):
|
|
project = get_object_or_404(Project, pk=pk)
|
|
if request.method == 'POST':
|
|
form = ProjectForm(request.POST, instance=project)
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, 'Proyecto actualizado exitosamente.')
|
|
return redirect('gestion_panel')
|
|
else:
|
|
form = ProjectForm(instance=project)
|
|
return render(request, 'expenses/project_form.html', {'form': form})
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def project_delete(request, pk):
|
|
project = get_object_or_404(Project, pk=pk)
|
|
if request.method == 'POST':
|
|
project.delete()
|
|
messages.success(request, 'Proyecto eliminado.')
|
|
return redirect('gestion_panel')
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def category_create(request):
|
|
if request.method == 'POST':
|
|
form = CategoryForm(request.POST)
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, 'Categoría creada exitosamente.')
|
|
return redirect('gestion_panel')
|
|
else:
|
|
form = CategoryForm()
|
|
return render(request, 'expenses/category_form.html', {'form': form})
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def category_edit(request, pk):
|
|
category = get_object_or_404(Category, pk=pk)
|
|
if request.method == 'POST':
|
|
form = CategoryForm(request.POST, instance=category)
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, 'Categoría actualizada exitosamente.')
|
|
return redirect('gestion_panel')
|
|
else:
|
|
form = CategoryForm(instance=category)
|
|
return render(request, 'expenses/category_form.html', {'form': form})
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def category_delete(request, pk):
|
|
category = get_object_or_404(Category, pk=pk)
|
|
if request.method == 'POST':
|
|
category.delete()
|
|
messages.success(request, 'Categoría eliminada.')
|
|
return redirect('gestion_panel')
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def vendor_create(request):
|
|
if request.method == 'POST':
|
|
form = VendorForm(request.POST)
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, 'Proveedor creado exitosamente.')
|
|
return redirect('gestion_panel')
|
|
else:
|
|
form = VendorForm()
|
|
return render(request, 'expenses/vendor_form.html', {'form': form})
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def vendor_edit(request, pk):
|
|
vendor = get_object_or_404(Vendor, pk=pk)
|
|
if request.method == 'POST':
|
|
form = VendorForm(request.POST, instance=vendor)
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, 'Proveedor actualizado exitosamente.')
|
|
return redirect('gestion_panel')
|
|
else:
|
|
form = VendorForm(instance=vendor)
|
|
return render(request, 'expenses/vendor_form.html', {'form': form})
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def vendor_delete(request, pk):
|
|
vendor = get_object_or_404(Vendor, pk=pk)
|
|
if request.method == 'POST':
|
|
vendor.delete()
|
|
messages.success(request, 'Proveedor eliminado.')
|
|
return redirect('gestion_panel')
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def responsable_create(request):
|
|
if request.method == 'POST':
|
|
form = ResponsableForm(request.POST)
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, 'Responsable creado exitosamente.')
|
|
return redirect('gestion_panel')
|
|
else:
|
|
form = ResponsableForm()
|
|
return render(request, 'expenses/responsable_form.html', {'form': form})
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def responsable_edit(request, pk):
|
|
user = get_object_or_404(User, pk=pk)
|
|
if request.method == 'POST':
|
|
form = ResponsableForm(request.POST, instance=user)
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, 'Responsable actualizado exitosamente.')
|
|
return redirect('gestion_panel')
|
|
else:
|
|
form = ResponsableForm(instance=user)
|
|
return render(request, 'expenses/responsable_form.html', {'form': form, 'edit_mode': True, 'target_user': user})
|
|
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def responsable_delete(request, pk):
|
|
user = get_object_or_404(User, pk=pk)
|
|
if request.method == 'POST':
|
|
user.delete()
|
|
messages.success(request, 'Responsable eliminado.')
|
|
return redirect('gestion_panel')
|
|
|
|
|
|
from django.db.models import Sum, Count
|
|
|
|
@login_required
|
|
def accounts_payable(request):
|
|
user_groups = request.user.groups.values_list('name', flat=True)
|
|
is_finanzas = 'Administrador Finanzas' in user_groups or request.user.is_superuser or 'Administrador' in user_groups
|
|
if not is_finanzas:
|
|
messages.error(request, 'No tienes permisos para ver Cuentas por Pagar.')
|
|
return redirect('dashboard')
|
|
|
|
debts = Expense.objects.filter(approval_status=ApprovalStatusEnum.SOLICITADO_FINANZAS).exclude(vendor__isnull=True).values(
|
|
'vendor__id', 'vendor__rut', 'vendor__name', 'vendor__bank', 'vendor__account_type', 'vendor__account_number'
|
|
).annotate(
|
|
total_clp=Sum('total_amount_clp'),
|
|
total_usd=Sum('amount_usd'),
|
|
expense_count=Count('id')
|
|
).order_by('-total_clp')
|
|
|
|
return render(request, 'expenses/accounts_payable.html', {'debts': debts})
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def category_create(request):
|
|
if request.method == 'POST':
|
|
form = CategoryForm(request.POST)
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, 'Categoría creada exitosamente.')
|
|
return redirect('gestion_panel')
|
|
else:
|
|
form = CategoryForm()
|
|
return render(request, 'expenses/category_form.html', {'form': form})
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def category_edit(request, pk):
|
|
category = get_object_or_404(Category, pk=pk)
|
|
if request.method == 'POST':
|
|
form = CategoryForm(request.POST, instance=category)
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, 'Categoría actualizada exitosamente.')
|
|
return redirect('gestion_panel')
|
|
else:
|
|
form = CategoryForm(instance=category)
|
|
return render(request, 'expenses/category_form.html', {'form': form})
|
|
|
|
@login_required
|
|
@role_required('Administrador')
|
|
def category_delete(request, pk):
|
|
category = get_object_or_404(Category, pk=pk)
|
|
if request.method == 'POST':
|
|
category.delete()
|
|
messages.success(request, 'Categoría eliminada.')
|
|
return redirect('gestion_panel')
|
|
|
|
@login_required
|
|
def delete_document(request, pk):
|
|
if request.method == 'POST':
|
|
doc = get_object_or_404(Document, pk=pk)
|
|
|
|
# Permissions check
|
|
user_groups = request.user.groups.values_list('name', flat=True)
|
|
if not (request.user.is_superuser or 'Administrador' in user_groups or doc.expense.user == request.user):
|
|
return JsonResponse({'success': False, 'error': 'No tienes permisos para eliminar este documento.'}, status=403)
|
|
|
|
# Status check
|
|
if doc.expense.approval_status in [ApprovalStatusEnum.SOLICITADO_FINANZAS, ApprovalStatusEnum.LIBERADO_PAGADO]:
|
|
return JsonResponse({'success': False, 'error': 'No puedes eliminar evidencias de un gasto en finanzas o pagado.'}, status=400)
|
|
|
|
# Delete file
|
|
if doc.file:
|
|
try:
|
|
if os.path.exists(doc.file.path):
|
|
os.remove(doc.file.path)
|
|
except Exception:
|
|
pass
|
|
|
|
# Delete object
|
|
doc.delete()
|
|
return JsonResponse({'success': True})
|
|
return JsonResponse({'success': False, 'error': 'Método no permitido.'}, status=405)
|