MVP final

This commit is contained in:
Nachou-u
2026-08-20 21:01:12 -04:00
parent 08a26cbf2f
commit 66655fb05c
10 changed files with 593 additions and 32 deletions
+98 -9
View File
@@ -4,25 +4,40 @@ from .models import Expense, Project, Category, SystemSetting, UserProfile, Docu
from .chile_regions import REGION_CHOICES, COMMUNE_CHOICES
from decimal import Decimal
import os
class MultipleFileInput(forms.FileInput):
allow_multiple_selected = True
class MultipleFileField(forms.FileField):
def __init__(self, *args, **kwargs):
kwargs.setdefault("widget", MultipleFileInput(attrs={'multiple': True, 'accept': 'image/*,.pdf'}))
super().__init__(*args, **kwargs)
def clean(self, data, initial=None):
single_file_clean = super().clean
if isinstance(data, (list, tuple)):
result = [single_file_clean(d, initial) for d in data]
else:
result = single_file_clean(data, initial)
return result
class ExpenseForm(forms.ModelForm):
date = forms.DateField(
widget=forms.DateInput(attrs={'type': 'date'}),
label='Fecha del Gasto'
)
amount_clp = forms.DecimalField(
amount_clp = forms.CharField(
label='Monto Neto (CLP)',
required=True,
widget=forms.NumberInput(attrs={'placeholder': 'Ej: 1450000'})
widget=forms.TextInput(attrs={'placeholder': 'Ej: 1.450.000'})
)
receipt = forms.FileField(
receipt = MultipleFileField(
label='Adjuntar Evidencia(s) (Boleta / Factura)',
required=False,
widget=MultipleFileInput(attrs={'multiple': True, 'accept': 'image/*,.pdf'})
required=False
)
region = forms.ChoiceField(
@@ -43,16 +58,28 @@ class ExpenseForm(forms.ModelForm):
required=False
)
tax_amount_clp = forms.DecimalField(
tax_amount_clp = forms.CharField(
label='Monto Impuesto (CLP)',
required=False,
widget=forms.NumberInput(attrs={'readonly': 'readonly'})
widget=forms.TextInput(attrs={'readonly': 'readonly'})
)
total_amount_clp = forms.DecimalField(
total_amount_clp = forms.CharField(
label='Monto Total (CLP)',
required=False,
widget=forms.NumberInput(attrs={'readonly': 'readonly'})
widget=forms.TextInput(attrs={'readonly': 'readonly'})
)
new_vendor_rut = forms.CharField(
label="RUT Nuevo Proveedor",
required=False,
widget=forms.TextInput(attrs={'placeholder': 'Ej: 76.543.210-K', 'id': 'id_new_vendor_rut'})
)
new_vendor_name = forms.CharField(
label="Nombre / Razón Social Nuevo Proveedor",
required=False,
widget=forms.TextInput(attrs={'placeholder': 'Ej: IMPORTADORA SPA', 'id': 'id_new_vendor_name'})
)
class Meta:
@@ -65,6 +92,68 @@ class ExpenseForm(forms.ModelForm):
'description': forms.Textarea(attrs={'rows': 3, 'placeholder': 'Ej: Carga combustible Copec / Pasajes bus terreno'}),
}
def clean_amount_clp(self):
data = self.cleaned_data.get('amount_clp', '')
if not data:
raise forms.ValidationError("Este campo es obligatorio.")
data_clean = str(data).replace('.', '').replace(',', '.')
try:
return Decimal(data_clean)
except Exception:
raise forms.ValidationError("Ingrese un monto válido (ej: 1.450.000).")
def clean_tax_amount_clp(self):
data = self.cleaned_data.get('tax_amount_clp', '')
if not data:
return Decimal('0.00')
data_clean = str(data).replace('.', '').replace(',', '.')
try:
return Decimal(data_clean)
except Exception:
return Decimal('0.00')
def clean_total_amount_clp(self):
data = self.cleaned_data.get('total_amount_clp', '')
if not data:
return Decimal('0.00')
data_clean = str(data).replace('.', '').replace(',', '.')
try:
return Decimal(data_clean)
except Exception:
return Decimal('0.00')
def clean_receipt(self):
files = self.files.getlist('receipt')
for f in files:
ext = os.path.splitext(f.name)[1].lower()
if ext not in ['.pdf', '.png', '.jpg', '.jpeg']:
raise forms.ValidationError(f"El archivo '{f.name}' no tiene una extensión permitida (PDF, PNG, JPG, JPEG).")
return self.cleaned_data.get('receipt')
def clean(self):
cleaned_data = super().clean()
new_name = cleaned_data.get('new_vendor_name')
new_rut = cleaned_data.get('new_vendor_rut')
if (new_name and not new_rut) or (new_rut and not new_name):
raise forms.ValidationError("Si desea registrar un nuevo proveedor, debe ingresar tanto el RUT como la Razón Social.")
return cleaned_data
def save(self, commit=True):
instance = super().save(commit=False)
new_name = self.cleaned_data.get('new_vendor_name')
new_rut = self.cleaned_data.get('new_vendor_rut')
if new_name and new_rut:
from .models import Vendor
vendor, _ = Vendor.objects.get_or_create(
rut=new_rut.strip(),
defaults={'name': new_name.strip()}
)
instance.vendor = vendor
if commit:
instance.save()
return instance
class ProjectForm(forms.ModelForm):
class Meta: