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
+166
View File
@@ -0,0 +1,166 @@
# Generated by Django 6.1 on 2026-09-07 02:50
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('expenses', '0010_alter_expense_amount_usd'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='ItemCatalog',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('code', models.CharField(max_length=50, unique=True, verbose_name='Código Ítem (CAT-XXX-XX)')),
('name', models.CharField(max_length=200, verbose_name='Descripción del Bien / Servicio')),
('unit', models.CharField(choices=[('UN', 'Unidad (UN)'), ('MES', 'Mes de Servicio'), ('DIA', 'Día / Jornada'), ('HORA', 'Hora Especialista'), ('LITRO', 'Litros'), ('GLB', 'Servicio Global'), ('LIC', 'Licencia Anual / Mensual')], default='UN', max_length=20, verbose_name='Unidad de Medida')),
('reference_price_clp', models.DecimalField(decimal_places=2, max_digits=12, verbose_name='Precio Referencial Neto (CLP)')),
('reference_price_usd', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='Precio Referencial (USD)')),
('sla_days', models.IntegerField(default=3, verbose_name='SLA / Plazo de Entrega (Días)')),
('specifications', models.TextField(blank=True, verbose_name='Especificaciones Técnicas')),
('is_active', models.BooleanField(default=True, verbose_name='Ítem Activo en Catálogo')),
('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='catalog_items', to='expenses.category', verbose_name='Categoría Contable')),
('preferred_vendor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='catalog_items', to='expenses.vendor', verbose_name='Proveedor Homologado / Preferido')),
],
options={
'verbose_name': 'Ítem de Catálogo',
'verbose_name_plural': 'Catálogo de Ítems y Servicios',
'ordering': ['code'],
},
),
migrations.CreateModel(
name='PurchaseOrder',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('code', models.CharField(default='OC-2026-0001', max_length=50, unique=True, verbose_name='Correlativo OC')),
('issue_date', models.DateField(verbose_name='Fecha de Emisión')),
('expected_delivery_date', models.DateField(blank=True, null=True, verbose_name='Fecha Estimada de Entrega')),
('payment_terms', models.CharField(default='30 Días Contra Factura', max_length=100, verbose_name='Condiciones de Pago')),
('delivery_address', models.CharField(default='Casa Matriz EFINTEL / Terreno Faena', max_length=255, verbose_name='Lugar de Entrega')),
('net_amount_clp', models.DecimalField(decimal_places=2, default=0, max_digits=15, verbose_name='Monto Neto (CLP)')),
('tax_rate', models.DecimalField(decimal_places=2, default=19.0, max_digits=5, verbose_name='Tasa IVA (%)')),
('tax_amount_clp', models.DecimalField(decimal_places=2, default=0, max_digits=15, verbose_name='Monto IVA (CLP)')),
('total_amount_clp', models.DecimalField(decimal_places=2, default=0, max_digits=15, verbose_name='Monto Total (CLP)')),
('status', models.CharField(choices=[('EMITIDA', 'Emitida'), ('ENVIADA_PROVEEDOR', 'Enviada al Proveedor'), ('RECEPCION_PARCIAL', 'Recepción Parcial'), ('RECEPCION_TOTAL', 'Recepción Conforme Total'), ('CONCILIADA_MATCH', '3-Way Match Conciliado'), ('CANCELADA', 'Cancelada')], default='EMITIDA', max_length=30, verbose_name='Estado de Orden de Compra')),
('terms_and_conditions', models.TextField(blank=True, verbose_name='Términos y Condiciones Especiales')),
('notes', models.TextField(blank=True, verbose_name='Notas Internas')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('issuer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='issued_purchase_orders', to=settings.AUTH_USER_MODEL, verbose_name='Emitido por')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='purchase_orders', to='expenses.project', verbose_name='Proyecto')),
('vendor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='purchase_orders', to='expenses.vendor', verbose_name='Proveedor')),
],
options={
'verbose_name': 'Orden de Compra',
'verbose_name_plural': 'Órdenes de Compra (OC)',
'ordering': ['-issue_date', '-created_at'],
},
),
migrations.CreateModel(
name='GoodsReceipt',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('code', models.CharField(default='REC-2026-0001', max_length=50, unique=True, verbose_name='N° Acta Recepción')),
('dispatch_guide_number', models.CharField(max_length=50, verbose_name='N° Guía de Despacho / Acta Terreno')),
('receipt_date', models.DateField(verbose_name='Fecha de Recepción')),
('technical_conformity', models.BooleanField(default=True, verbose_name='Conformidad Técnica Aprobada')),
('notes', models.TextField(blank=True, verbose_name='Observaciones de Entrega / Inspección')),
('created_at', models.DateTimeField(auto_now_add=True)),
('received_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='received_deliveries', to=settings.AUTH_USER_MODEL, verbose_name='Receptor Conforme')),
('purchase_order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='receipts', to='procurement.purchaseorder', verbose_name='Orden de Compra')),
],
options={
'verbose_name': 'Recepción de Bienes / Servicios',
'verbose_name_plural': 'Recepciones de Bienes y Servicios',
'ordering': ['-receipt_date'],
},
),
migrations.CreateModel(
name='PurchaseOrderItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('description', models.CharField(max_length=255, verbose_name='Descripción del Bien / Servicio')),
('quantity', models.DecimalField(decimal_places=2, default=1, max_digits=10, verbose_name='Cantidad')),
('unit_price_net', models.DecimalField(decimal_places=2, max_digits=12, verbose_name='Precio Unitario Neto (CLP)')),
('subtotal_net', models.DecimalField(decimal_places=2, default=0, max_digits=12, verbose_name='Subtotal Neto (CLP)')),
('catalog_item', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='procurement.itemcatalog', verbose_name='Ítem del Catálogo')),
('purchase_order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='procurement.purchaseorder', verbose_name='Orden de Compra')),
],
),
migrations.CreateModel(
name='PurchaseRequisition',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('code', models.CharField(default='REQ-2026-0001', max_length=50, unique=True, verbose_name='Código Requisición')),
('purpose', models.TextField(verbose_name='Justificación Técnica y Destino I+D+i')),
('priority', models.CharField(choices=[('BAJA', 'Baja'), ('MEDIA', 'Media'), ('ALTA', 'Alta'), ('CRITICA', 'Crítica / Faena Urgente')], default='MEDIA', max_length=30, verbose_name='Prioridad')),
('status', models.CharField(choices=[('BORRADOR', 'Borrador'), ('SOLICITADA', 'Solicitada (Pendiente Aprobación)'), ('APROBADA_TECNICA', 'Aprobada Técnicamente'), ('APROBADA_FINANZAS', 'Aprobada por Finanzas'), ('RECHAZADA', 'Rechazada'), ('CONVERTIDA_OC', 'Orden de Compra Generada')], default='BORRADOR', max_length=30, verbose_name='Estado de Aprobación')),
('required_date', models.DateField(verbose_name='Fecha Requerida en Sitio')),
('approved_at', models.DateTimeField(blank=True, null=True, verbose_name='Fecha de Aprobación')),
('rejection_reason', models.TextField(blank=True, verbose_name='Motivo de Rechazo')),
('total_estimated_clp', models.DecimalField(decimal_places=2, default=0, max_digits=15, verbose_name='Total Estimado Neto (CLP)')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('approved_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='approved_requisitions', to=settings.AUTH_USER_MODEL, verbose_name='Aprobado por')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='purchase_requisitions', to='expenses.project', verbose_name='Proyecto / Centro de Costo')),
('requester', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='purchase_requisitions', to=settings.AUTH_USER_MODEL, verbose_name='Solicitante')),
],
options={
'verbose_name': 'Requisición de Compra',
'verbose_name_plural': 'Requisiciones de Compra',
'ordering': ['-created_at'],
},
),
migrations.AddField(
model_name='purchaseorder',
name='requisition',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='purchase_orders', to='procurement.purchaserequisition', verbose_name='Requisición de Origen'),
),
migrations.CreateModel(
name='RequisitionItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('description', models.CharField(max_length=255, verbose_name='Descripción / Detalle')),
('quantity', models.DecimalField(decimal_places=2, default=1, max_digits=10, verbose_name='Cantidad')),
('unit_price', models.DecimalField(decimal_places=2, max_digits=12, verbose_name='Precio Unitario Estimado (CLP)')),
('subtotal', models.DecimalField(decimal_places=2, default=0, max_digits=12, verbose_name='Subtotal (CLP)')),
('catalog_item', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='requisition_items', to='procurement.itemcatalog', verbose_name='Ítem del Catálogo')),
('requisition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='procurement.purchaserequisition', verbose_name='Requisición')),
],
),
migrations.CreateModel(
name='ThreeWayMatch',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('dte_invoice_number', models.CharField(max_length=50, verbose_name='N° Factura Electrónica (DTE 33)')),
('dte_invoice_rut', models.CharField(max_length=20, verbose_name='RUT Emisor Factura')),
('dte_invoice_date', models.DateField(verbose_name='Fecha Emisión Factura')),
('dte_net_amount', models.DecimalField(decimal_places=2, max_digits=15, verbose_name='Monto Neto Factura (CLP)')),
('dte_tax_amount', models.DecimalField(decimal_places=2, max_digits=15, verbose_name='Monto IVA Factura (CLP)')),
('dte_total_amount', models.DecimalField(decimal_places=2, max_digits=15, verbose_name='Monto Total Factura (CLP)')),
('price_difference_clp', models.DecimalField(decimal_places=2, default=0, max_digits=12, verbose_name='Diferencia de Monto Neto (CLP)')),
('quantity_difference', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='Diferencia en Cantidades')),
('match_status', models.CharField(choices=[('MATCH_PERFECTO', 'Match Perfecto (Tolerancia 0% OK)'), ('DISCREPANCIA_PRECIO', 'Discrepancia en Precio / Monto Neto'), ('DISCREPANCIA_CANTIDAD', 'Discrepancia en Cantidades Recibidas'), ('PENDIENTE_RECEPCION', 'Pendiente de Recepción en Bodega/Faena'), ('RECHAZADO', 'Rechazado por Auditoría')], default='PENDIENTE_RECEPCION', max_length=30, verbose_name='Resultado del 3-Way Match')),
('matched_at', models.DateTimeField(blank=True, null=True, verbose_name='Fecha de Conciliación')),
('resolution_notes', models.TextField(blank=True, verbose_name='Notas de Resolución / Observación Contable')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('goods_receipt', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='matches', to='procurement.goodsreceipt', verbose_name='Recepción Conforme')),
('matched_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Auditor / Conciliador')),
('purchase_order', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='three_way_match', to='procurement.purchaseorder', verbose_name='Orden de Compra')),
],
options={
'verbose_name': 'Conciliación 3-Way Match',
'verbose_name_plural': 'Conciliaciones 3-Way Match (Tolerancia 0%)',
'ordering': ['-created_at'],
},
),
]
View File