MVP final
This commit is contained in:
+98
-9
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user