iteracion 2
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user