CORRECCIÓN: Changed dangerous CASCADE deletions to PROTECT on critical FKs

This commit is contained in:
Nachou-u
2026-09-09 08:27:49 -03:00
parent c229da1436
commit 5d9e0f4589
4 changed files with 19 additions and 19 deletions
+9 -9
View File
@@ -63,7 +63,7 @@ class CatalogModel(TimeStampedModel):
class Project(CatalogModel):
manager = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='managed_projects', verbose_name="Encargado / Director")
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children', verbose_name="Portafolio / Proyecto Padre")
parent = models.ForeignKey('self', on_delete=models.PROTECT, null=True, blank=True, related_name='children', verbose_name="Portafolio / Proyecto Padre")
assigned_budget_clp = models.DecimalField(max_digits=15, decimal_places=2, default=0, verbose_name="Presupuesto Asignado (CLP)")
assigned_budget_usd = models.DecimalField(max_digits=15, decimal_places=2, default=0, verbose_name="Presupuesto Asignado (USD)")
@@ -101,7 +101,7 @@ class Project(CatalogModel):
class ProjectPhase(TimeStampedModel):
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='phases', verbose_name="Proyecto")
project = models.ForeignKey(Project, on_delete=models.PROTECT, related_name='phases', verbose_name="Proyecto")
phase_number = models.IntegerField(default=1, verbose_name="N° Fase / Hito")
name = models.CharField(max_length=150, verbose_name="Nombre de la Fase / Hito")
description = models.TextField(blank=True, verbose_name="Descripción de Entregables")
@@ -126,7 +126,7 @@ class ProjectPhase(TimeStampedModel):
class Category(CatalogModel):
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children', verbose_name="Categoría Padre")
parent = models.ForeignKey('self', on_delete=models.PROTECT, null=True, blank=True, related_name='children', verbose_name="Categoría Padre")
def __str__(self):
return f"{self.code}: {self.name}"
@@ -161,8 +161,8 @@ class Vendor(TimeStampedModel):
class ExpenseReport(models.Model):
report_code = models.CharField(max_length=50, unique=True, verbose_name="Código Rendición", default="EXP-REP-001")
title = models.CharField(max_length=250, verbose_name="Título del Informe / Viaje")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='expense_reports', verbose_name="Responsable Rendidor")
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='expense_reports', verbose_name="Proyecto Imputado")
user = models.ForeignKey(User, on_delete=models.PROTECT, related_name='expense_reports', verbose_name="Responsable Rendidor")
project = models.ForeignKey(Project, on_delete=models.PROTECT, related_name='expense_reports', verbose_name="Proyecto Imputado")
start_date = models.DateField(verbose_name="Fecha de Inicio")
end_date = models.DateField(verbose_name="Fecha de Término")
@@ -201,7 +201,7 @@ class ExpenseReport(models.Model):
class Expense(TimeStampedModel):
expense_code = models.CharField(max_length=50, unique=True, default=uuid.uuid4, verbose_name="Código Transacción")
report = models.ForeignKey(ExpenseReport, on_delete=models.SET_NULL, null=True, blank=True, related_name='expenses', verbose_name="Informe de Rendición (Opcional)")
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='expenses', verbose_name="Proyecto")
project = models.ForeignKey(Project, on_delete=models.PROTECT, related_name='expenses', verbose_name="Proyecto")
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, blank=True, related_name='expenses', verbose_name="Subcategoría")
document_number = models.CharField(max_length=50, blank=True, null=True, verbose_name="N° Folio Boleta / Factura")
@@ -228,7 +228,7 @@ class Expense(TimeStampedModel):
approval_status = models.CharField(max_length=50, choices=ApprovalStatusEnum.choices, default=ApprovalStatusEnum.EN_REVISION, verbose_name="Estado de Aprobación")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='expenses_created', verbose_name="Registrado por")
user = models.ForeignKey(User, on_delete=models.PROTECT, related_name='expenses_created', verbose_name="Registrado por")
responsible_person = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='expenses_responsible', verbose_name="Responsable Solicitante / Rendidor")
elevated_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='expenses_elevated', verbose_name="Elevado por (Paso 2)")
paid_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='expenses_paid', verbose_name="Pagado por (Paso 3)")
@@ -289,7 +289,7 @@ class Expense(TimeStampedModel):
class VehicleLog(models.Model):
expense = models.OneToOneField(Expense, on_delete=models.CASCADE, related_name='vehicle_log', null=True, blank=True, verbose_name="Gasto Asociado")
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='vehicle_logs', verbose_name="Proyecto")
project = models.ForeignKey(Project, on_delete=models.PROTECT, related_name='vehicle_logs', verbose_name="Proyecto")
license_plate = models.CharField(max_length=20, verbose_name="Patente Vehículo")
driver_name = models.CharField(max_length=150, verbose_name="Nombre Conductor")
@@ -350,7 +350,7 @@ class Document(models.Model):
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile', verbose_name="Usuario")
user = models.OneToOneField(User, on_delete=models.PROTECT, related_name='profile', verbose_name="Usuario")
rut = models.CharField(max_length=20, blank=True, null=True, verbose_name="RUT")
job_title = models.CharField(max_length=150, blank=True, null=True, verbose_name="Cargo")
description = models.TextField(blank=True, verbose_name="Descripción del Responsable")
+1 -1
View File
@@ -107,7 +107,7 @@ class SalarySlip(models.Model):
Impuesto Único de Segunda Categoría SII y Aportes Patronales (SIS, Mutual, AFC).
"""
slip_uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
employee = models.ForeignKey(EmployeeProfile, on_delete=models.CASCADE, related_name='salary_slips', verbose_name="Colaborador")
employee = models.ForeignKey(EmployeeProfile, on_delete=models.PROTECT, related_name='salary_slips', verbose_name="Colaborador")
month = models.IntegerField(verbose_name="Mes (1-12)")
year = models.IntegerField(verbose_name="Año (ej. 2026)")
+8 -8
View File
@@ -75,8 +75,8 @@ class PurchaseRequisition(models.Model):
Inicia el flujo de abastecimiento y aprobación técnica/financiera.
"""
code = models.CharField(max_length=50, unique=True, verbose_name="Código Requisición", default="REQ-2026-0001")
requester = models.ForeignKey(User, on_delete=models.CASCADE, related_name='purchase_requisitions', verbose_name="Solicitante")
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='purchase_requisitions', verbose_name="Proyecto / Centro de Costo")
requester = models.ForeignKey(User, on_delete=models.PROTECT, related_name='purchase_requisitions', verbose_name="Solicitante")
project = models.ForeignKey(Project, on_delete=models.PROTECT, related_name='purchase_requisitions', verbose_name="Proyecto / Centro de Costo")
purpose = models.TextField(verbose_name="Justificación Técnica y Destino I+D+i")
priority = models.CharField(max_length=30, choices=RequisitionPriorityEnum.choices, default=RequisitionPriorityEnum.MEDIA, verbose_name="Prioridad")
@@ -130,9 +130,9 @@ class PurchaseOrder(models.Model):
"""
code = models.CharField(max_length=50, unique=True, verbose_name="Correlativo OC", default="OC-2026-0001")
requisition = models.ForeignKey(PurchaseRequisition, on_delete=models.SET_NULL, null=True, blank=True, related_name='purchase_orders', verbose_name="Requisición de Origen")
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, related_name='purchase_orders', verbose_name="Proveedor")
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='purchase_orders', verbose_name="Proyecto")
issuer = models.ForeignKey(User, on_delete=models.CASCADE, related_name='issued_purchase_orders', verbose_name="Emitido por")
vendor = models.ForeignKey(Vendor, on_delete=models.PROTECT, related_name='purchase_orders', verbose_name="Proveedor")
project = models.ForeignKey(Project, on_delete=models.PROTECT, related_name='purchase_orders', verbose_name="Proyecto")
issuer = models.ForeignKey(User, on_delete=models.PROTECT, related_name='issued_purchase_orders', verbose_name="Emitido por")
issue_date = models.DateField(verbose_name="Fecha de Emisión")
expected_delivery_date = models.DateField(null=True, blank=True, verbose_name="Fecha Estimada de Entrega")
@@ -191,10 +191,10 @@ class GoodsReceipt(models.Model):
Recepción Conforme en Bodega o Terreno.
"""
code = models.CharField(max_length=50, unique=True, verbose_name="N° Acta Recepción", default="REC-2026-0001")
purchase_order = models.ForeignKey(PurchaseOrder, on_delete=models.CASCADE, related_name='receipts', verbose_name="Orden de Compra")
purchase_order = models.ForeignKey(PurchaseOrder, on_delete=models.PROTECT, related_name='receipts', verbose_name="Orden de Compra")
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")
received_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='received_deliveries', verbose_name="Receptor Conforme")
received_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name='received_deliveries', verbose_name="Receptor Conforme")
technical_conformity = models.BooleanField(default=True, verbose_name="Conformidad Técnica Aprobada")
notes = models.TextField(blank=True, verbose_name="Observaciones de Entrega / Inspección")
@@ -217,7 +217,7 @@ class ThreeWayMatch(models.Model):
2. Recepción Física (Guía de Despacho / Acta de Conformidad)
3. Factura Electrónica SII (DTE 33)
"""
purchase_order = models.OneToOneField(PurchaseOrder, on_delete=models.CASCADE, related_name='three_way_match', verbose_name="Orden de Compra")
purchase_order = models.OneToOneField(PurchaseOrder, on_delete=models.PROTECT, related_name='three_way_match', verbose_name="Orden de Compra")
goods_receipt = models.ForeignKey(GoodsReceipt, on_delete=models.SET_NULL, null=True, blank=True, related_name='matches', verbose_name="Recepción Conforme")
# Datos Factura Electrónica SII DTE 33
+1 -1
View File
@@ -107,7 +107,7 @@ class EvaluationRubric7D(models.Model):
7. Capacidad de Innovación e I+D+i: 10%
Vigencia: 12 meses.
"""
candidate = models.ForeignKey(SpecialistCandidate, on_delete=models.CASCADE, related_name='evaluations', verbose_name="Especialista Candidato")
candidate = models.ForeignKey(SpecialistCandidate, on_delete=models.PROTECT, related_name='evaluations', verbose_name="Especialista Candidato")
evaluator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="Evaluador Líder")
evaluation_date = models.DateField(default=date.today, verbose_name="Fecha de Evaluación")