iteracion 2

This commit is contained in:
Nachou-u
2026-09-07 18:44:32 -03:00
parent a103a47ae6
commit 09a3f6fb37
93 changed files with 7394 additions and 349 deletions
+134
View File
@@ -0,0 +1,134 @@
from django import forms
from .models import ItemCatalog, PurchaseRequisition, RequisitionItem, PurchaseOrder, PurchaseOrderItem, GoodsReceipt, ThreeWayMatch
from expenses.models import Project, Vendor, Category
from decimal import Decimal
class ItemCatalogForm(forms.ModelForm):
class Meta:
model = ItemCatalog
fields = ['code', 'name', 'category', 'unit', 'reference_price_clp', 'reference_price_usd', 'sla_days', 'preferred_vendor', 'specifications', 'is_active']
widgets = {
'code': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'CAT-XXX-01', 'required': 'required', 'pattern': 'CAT-[A-Z0-9]+-[0-9]+'}),
'name': forms.TextInput(attrs={'class': 'form-control', 'required': 'required', 'minlength': '3'}),
'category': forms.Select(attrs={'class': 'form-control', 'required': 'required'}),
'unit': forms.Select(attrs={'class': 'form-control', 'required': 'required'}),
'reference_price_clp': forms.NumberInput(attrs={'class': 'form-control', 'step': '1000', 'required': 'required', 'min': '0'}),
'reference_price_usd': forms.NumberInput(attrs={'class': 'form-control', 'step': '1', 'min': '0'}),
'sla_days': forms.NumberInput(attrs={'class': 'form-control', 'required': 'required', 'min': '0'}),
'preferred_vendor': forms.Select(attrs={'class': 'form-control'}),
'specifications': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
}
def clean_reference_price_clp(self):
val = self.cleaned_data.get('reference_price_clp')
if val is not None and val < 0:
raise forms.ValidationError("El precio no puede ser negativo.")
return val
class PurchaseRequisitionForm(forms.ModelForm):
required_date = forms.DateField(
widget=forms.DateInput(attrs={'type': 'date', 'class': 'form-control', 'required': 'required'}),
label="Fecha Requerida en Sitio / Faena"
)
class Meta:
model = PurchaseRequisition
fields = ['project', 'purpose', 'priority', 'required_date']
widgets = {
'project': forms.Select(attrs={'class': 'form-control', 'required': 'required'}),
'purpose': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': 'Describa el objetivo técnico y la necesidad para el proyecto...', 'required': 'required', 'minlength': '10'}),
'priority': forms.Select(attrs={'class': 'form-control', 'required': 'required'}),
}
class PurchaseOrderForm(forms.ModelForm):
issue_date = forms.DateField(
widget=forms.DateInput(attrs={'type': 'date', 'class': 'form-control', 'required': 'required'}),
label="Fecha de Emisión"
)
expected_delivery_date = forms.DateField(
widget=forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
label="Fecha Estimada de Entrega",
required=False
)
class Meta:
model = PurchaseOrder
fields = ['requisition', 'vendor', 'project', 'issue_date', 'expected_delivery_date', 'payment_terms', 'delivery_address', 'terms_and_conditions', 'notes']
widgets = {
'requisition': forms.Select(attrs={'class': 'form-control', 'required': 'required'}),
'vendor': forms.Select(attrs={'class': 'form-control', 'required': 'required'}),
'project': forms.Select(attrs={'class': 'form-control', 'required': 'required'}),
'payment_terms': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ej: 30 Días Contra Factura', 'required': 'required'}),
'delivery_address': forms.TextInput(attrs={'class': 'form-control', 'id': 'id_delivery_address', 'required': 'required'}),
'terms_and_conditions': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 2}),
}
def clean(self):
cleaned_data = super().clean()
issue = cleaned_data.get('issue_date')
expected = cleaned_data.get('expected_delivery_date')
if issue and expected and expected < issue:
raise forms.ValidationError("La fecha de entrega esperada no puede ser anterior a la fecha de emisión.")
return cleaned_data
class GoodsReceiptForm(forms.ModelForm):
receipt_date = forms.DateField(
widget=forms.DateInput(attrs={'type': 'date', 'class': 'form-control', 'required': 'required'}),
label="Fecha de Recepción"
)
class Meta:
model = GoodsReceipt
fields = ['purchase_order', 'dispatch_guide_number', 'receipt_date', 'technical_conformity', 'notes']
widgets = {
'purchase_order': forms.Select(attrs={'class': 'form-control', 'required': 'required'}),
'dispatch_guide_number': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'N° Guía de Despacho o Acta Terreno', 'required': 'required'}),
'technical_conformity': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': 'Observaciones de estado físico, embalaje o pruebas de funcionamiento...'}),
}
class ThreeWayMatchForm(forms.ModelForm):
dte_invoice_date = forms.DateField(
widget=forms.DateInput(attrs={'type': 'date', 'class': 'form-control', 'required': 'required'}),
label="Fecha Emisión Factura SII"
)
class Meta:
model = ThreeWayMatch
fields = [
'purchase_order', 'goods_receipt', 'dte_invoice_number', 'dte_invoice_rut',
'dte_invoice_date', 'dte_net_amount', 'dte_tax_amount', 'dte_total_amount',
'resolution_notes'
]
widgets = {
'purchase_order': forms.Select(attrs={'class': 'form-control', 'id': 'id_po_select', 'required': 'required'}),
'goods_receipt': forms.Select(attrs={'class': 'form-control', 'required': 'required'}),
'dte_invoice_number': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ej: 45290', 'required': 'required', 'pattern': '^[0-9A-Za-z\-]+$'}),
'dte_invoice_rut': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ej: 76.543.210-K', 'required': 'required', 'pattern': '^\d{1,2}\.\d{3}\.\d{3}-[\dkK]$'}),
'dte_net_amount': forms.NumberInput(attrs={'class': 'form-control', 'step': '1', 'id': 'id_dte_net', 'required': 'required', 'min': '0'}),
'dte_tax_amount': forms.NumberInput(attrs={'class': 'form-control', 'step': '1', 'id': 'id_dte_tax', 'required': 'required', 'min': '0'}),
'dte_total_amount': forms.NumberInput(attrs={'class': 'form-control', 'step': '1', 'id': 'id_dte_total', 'required': 'required', 'min': '0'}),
'resolution_notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 2, 'placeholder': 'Comentarios de auditoría o justificación de diferencias...'}),
}
def clean_dte_invoice_rut(self):
rut = self.cleaned_data.get('dte_invoice_rut')
if not rut:
raise forms.ValidationError("Este campo es obligatorio.")
return rut.upper()
def clean(self):
cleaned_data = super().clean()
net = cleaned_data.get('dte_net_amount')
tax = cleaned_data.get('dte_tax_amount')
total = cleaned_data.get('dte_total_amount')
if net is not None and tax is not None and total is not None:
if net + tax != total:
raise forms.ValidationError("El Monto Total debe ser igual a la suma del Monto Neto y el Monto IVA.")
return cleaned_data