MVP 0.5 modificaciones finales
This commit is contained in:
+25
-4
@@ -131,8 +131,18 @@ def expense_create(request):
|
||||
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)
|
||||
import os
|
||||
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(
|
||||
user=request.user,
|
||||
@@ -183,8 +193,19 @@ def expense_edit(request, pk):
|
||||
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)
|
||||
import os
|
||||
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(
|
||||
user=request.user,
|
||||
|
||||
@@ -99,15 +99,17 @@
|
||||
</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 class="form-group">
|
||||
<label for="id_new_vendor_rut" style="font-weight: 600; font-size: 0.85rem; color: #166534;">RUT del Nuevo Proveedor</label>
|
||||
<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" style="display:flex; flex-direction:column;">
|
||||
<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 }}
|
||||
<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 %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="id_new_vendor_name" style="font-weight: 600; font-size: 0.85rem; color: #166534;">Nombre / Razón Social del Nuevo Proveedor</label>
|
||||
<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; margin-bottom: 0.35rem;">Nombre / Razón Social</label>
|
||||
{{ 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 %}
|
||||
</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>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user