MVP 0.5 modificaciones finales

This commit is contained in:
Nachou-u
2026-08-20 21:31:20 -04:00
parent 66655fb05c
commit a103a47ae6
2 changed files with 72 additions and 9 deletions
+25 -4
View File
@@ -131,8 +131,18 @@ def expense_create(request):
receipts = request.FILES.getlist('receipt') receipts = request.FILES.getlist('receipt')
if receipts: if receipts:
from .models import Document from .models import Document
for f in receipts: import os
Document.objects.create(expense=expense, file=f, title=f.name, uploaded_by=request.user) cat_name = expense.category.name if expense.category else 'Evidencia'
proj_code = expense.project.code if expense.project else 'PROY'
for idx, f in enumerate(receipts, start=1):
ext = os.path.splitext(f.name)[1].lower()
semantic_title = f"{proj_code} · {cat_name} · Doc {idx:02d}{ext}"
Document.objects.create(
expense=expense,
file=f,
title=semantic_title,
uploaded_by=request.user
)
AuditLog.objects.create( AuditLog.objects.create(
user=request.user, user=request.user,
@@ -183,8 +193,19 @@ def expense_edit(request, pk):
receipts = request.FILES.getlist('receipt') receipts = request.FILES.getlist('receipt')
if receipts: if receipts:
from .models import Document from .models import Document
for f in receipts: import os
Document.objects.create(expense=exp, file=f, title=f.name, uploaded_by=request.user) cat_name = exp.category.name if exp.category else 'Evidencia'
proj_code = exp.project.code if exp.project else 'PROY'
existing_count = exp.documents.count()
for idx, f in enumerate(receipts, start=existing_count + 1):
ext = os.path.splitext(f.name)[1].lower()
semantic_title = f"{proj_code} · {cat_name} · Doc {idx:02d}{ext}"
Document.objects.create(
expense=exp,
file=f,
title=semantic_title,
uploaded_by=request.user
)
AuditLog.objects.create( AuditLog.objects.create(
user=request.user, user=request.user,
+47 -5
View File
@@ -99,15 +99,17 @@
</div> </div>
</div> </div>
<div id="new-vendor-fields" style="display: none; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-bottom: 1.5rem; background: #f0fdf4; padding: 1.25rem; border-radius: 6px; border: 1px solid #bbf7d0; box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.05);"> <div id="new-vendor-fields" style="display: none; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-bottom: 1.5rem; background: #f0fdf4; padding: 1.25rem; border-radius: 6px; border: 1px solid #bbf7d0; box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.05); align-items: end;">
<div class="form-group"> <div class="form-group" style="display:flex; flex-direction:column;">
<label for="id_new_vendor_rut" style="font-weight: 600; font-size: 0.85rem; color: #166534;">RUT del Nuevo Proveedor</label> <label for="id_new_vendor_rut" style="font-weight: 600; font-size: 0.85rem; color: #166534; margin-bottom: 0.35rem;">RUT del Nuevo Proveedor</label>
{{ form.new_vendor_rut }} {{ form.new_vendor_rut }}
<small style="color: #166534; opacity: 0.7; font-size: 0.7rem; margin-top: 0.25rem;">Ej: 12.345.678-9</small>
{% if form.new_vendor_rut.errors %}<div style="color: var(--efintel-danger); font-size: 0.75rem; margin-top: 4px;">{{ form.new_vendor_rut.errors }}</div>{% endif %} {% if form.new_vendor_rut.errors %}<div style="color: var(--efintel-danger); font-size: 0.75rem; margin-top: 4px;">{{ form.new_vendor_rut.errors }}</div>{% endif %}
</div> </div>
<div class="form-group"> <div class="form-group" style="display:flex; flex-direction:column;">
<label for="id_new_vendor_name" style="font-weight: 600; font-size: 0.85rem; color: #166534;">Nombre / Razón Social del Nuevo Proveedor</label> <label for="id_new_vendor_name" style="font-weight: 600; font-size: 0.85rem; color: #166534; margin-bottom: 0.35rem;">Nombre / Razón Social</label>
{{ form.new_vendor_name }} {{ form.new_vendor_name }}
<small style="color: #166534; opacity: 0.7; font-size: 0.7rem; margin-top: 0.25rem;">Nombre legal del proveedor</small>
{% if form.new_vendor_name.errors %}<div style="color: var(--efintel-danger); font-size: 0.75rem; margin-top: 4px;">{{ form.new_vendor_name.errors }}</div>{% endif %} {% if form.new_vendor_name.errors %}<div style="color: var(--efintel-danger); font-size: 0.75rem; margin-top: 4px;">{{ form.new_vendor_name.errors }}</div>{% endif %}
</div> </div>
</div> </div>
@@ -682,6 +684,46 @@
} }
}); });
} }
// RUT Auto-formatter (XX.XXX.XXX-X)
const rutInput = document.getElementById('id_new_vendor_rut');
if (rutInput) {
rutInput.addEventListener('input', () => {
let val = rutInput.value.replace(/[^0-9kK]/g, '').toUpperCase();
if (val.length === 0) { rutInput.value = ''; return; }
// Separate body and verifier digit
const dv = val.slice(-1);
let body = val.slice(0, -1);
// Add thousands separator to body
body = body.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
rutInput.value = body ? `${body}-${dv}` : dv;
});
// Validate on blur: simple dv check using modulo 11
rutInput.addEventListener('blur', () => {
const raw = rutInput.value.replace(/\./g, '').replace(/-/g, '');
if (raw.length < 2) return;
const body = raw.slice(0, -1);
const dv = raw.slice(-1).toUpperCase();
let sum = 0, factor = 2;
for (let i = body.length - 1; i >= 0; i--) {
sum += parseInt(body[i]) * factor;
factor = factor === 7 ? 2 : factor + 1;
}
const remainder = 11 - (sum % 11);
const expectedDv = remainder === 11 ? '0' : remainder === 10 ? 'K' : String(remainder);
if (dv !== expectedDv) {
rutInput.style.border = '2px solid var(--efintel-danger)';
rutInput.title = `RUT inválido (dígito verificador esperado: ${expectedDv})`;
} else {
rutInput.style.border = '';
rutInput.title = '';
}
});
}
</script> </script>
{% endblock %} {% endblock %}