Feat: dashboard con gráficos, estructura CBS/Portafolios, semáforo de proyectos y cartera de especialistas

This commit is contained in:
Nachou-u
2026-08-20 18:54:58 -04:00
parent 8c0b435555
commit b692614857
25 changed files with 1717 additions and 159 deletions
+42 -3
View File
@@ -1,6 +1,6 @@
from django import forms
from django.contrib.auth.models import User, Group
from .models import Expense, Project, Category, SystemSetting, UserProfile, Document, CurrencyEnum, ExpenseTypeEnum
from .models import Expense, Project, Category, SystemSetting, UserProfile, Document, CurrencyEnum, ExpenseTypeEnum, Vendor
class ExpenseForm(forms.ModelForm):
@@ -21,10 +21,22 @@ class ExpenseForm(forms.ModelForm):
widget=forms.FileInput(attrs={'accept': 'image/*,.pdf'})
)
tax_amount_clp = forms.DecimalField(
label='Monto Impuesto (CLP)',
required=False,
widget=forms.NumberInput(attrs={'readonly': 'readonly'})
)
total_amount_clp = forms.DecimalField(
label='Monto Total (CLP)',
required=False,
widget=forms.NumberInput(attrs={'readonly': 'readonly'})
)
class Meta:
model = Expense
fields = [
'project', 'category', 'amount_clp', 'currency', 'date',
'project', 'category', 'amount_clp', 'tax_type', 'tax_amount_clp', 'total_amount_clp', 'currency', 'date',
'description', 'vendor', 'region', 'comuna', 'vehicle_ownership'
]
widgets = {
@@ -35,12 +47,27 @@ class ExpenseForm(forms.ModelForm):
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ['code', 'name', 'type', 'description', 'manager', 'assigned_budget_clp']
fields = ['code', 'name', 'parent', 'category', 'status', 'type', 'description', 'manager', 'assigned_budget_clp']
widgets = {
'description': forms.Textarea(attrs={'rows': 3}),
}
class CategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = ['code', 'name', 'parent', 'description']
widgets = {
'description': forms.Textarea(attrs={'rows': 3}),
}
class VendorForm(forms.ModelForm):
class Meta:
model = Vendor
fields = ['rut', 'name', 'business_line', 'bank', 'account_type', 'account_number', 'email', 'payment_terms']
class SystemSettingForm(forms.ModelForm):
class Meta:
model = SystemSetting
@@ -57,6 +84,12 @@ class ResponsableForm(forms.Form):
rut = forms.CharField(max_length=20, label="RUT", required=False)
job_title = forms.CharField(max_length=150, label="Cargo", required=False)
description = forms.CharField(widget=forms.Textarea(attrs={'rows': 3}), label="Descripción / Bio", required=False)
specialties = forms.ModelMultipleChoiceField(
queryset=Category.objects.all(),
required=False,
widget=forms.CheckboxSelectMultiple(),
label="Especialidades Técnicas (Categorías)"
)
def __init__(self, *args, **kwargs):
self.instance = kwargs.pop('instance', None)
@@ -73,6 +106,7 @@ class ResponsableForm(forms.Form):
self.fields['description'].initial = self.instance.profile.description
self.fields['rut'].initial = self.instance.profile.rut
self.fields['job_title'].initial = self.instance.profile.job_title
self.fields['specialties'].initial = self.instance.profile.specialties.all()
except Exception:
pass
# Password is optional for edit
@@ -124,6 +158,11 @@ class ResponsableForm(forms.Form):
profile.job_title = job_title
profile.save()
# Save specialties
specialties = self.cleaned_data.get('specialties')
if specialties is not None:
profile.specialties.set(specialties)
return user