feat: migración de datos de traspasos heredados
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
7fd2f3361d
commit
9af6e749d5
@ -0,0 +1,72 @@
|
|||||||
|
"""Convierte en Transfer los traspasos históricos que estaban sueltos.
|
||||||
|
|
||||||
|
Antes de que existiera Transfer, un traspaso eran dos movimientos marcados con
|
||||||
|
is_transfer pero sin nada que los relacionara: un Expense en la cuenta de origen
|
||||||
|
y un Income en la de destino. Aquí se emparejan y se les cuelga un Transfer.
|
||||||
|
|
||||||
|
No se pueden emparejar con certeza: nada en la base de datos dice qué gasto va
|
||||||
|
con qué ingreso. El criterio es mismo owner, mismo importe, misma fecha y cuentas
|
||||||
|
distintas, y solo cuando en ese grupo hay exactamente un gasto y un ingreso. Los
|
||||||
|
ambiguos (varios candidatos con el mismo importe y fecha) y los huérfanos (sin
|
||||||
|
pareja) se dejan tal cual, con su is_transfer=True: siguen contando en los saldos
|
||||||
|
y fuera de los análisis igual que antes, solo que sin Transfer que los orqueste.
|
||||||
|
Emparejarlos a ojo sería inventarse datos del usuario.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def link_legacy_transfers(apps, schema_editor):
|
||||||
|
Expense = apps.get_model("expenses", "Expense")
|
||||||
|
Income = apps.get_model("expenses", "Income")
|
||||||
|
Transfer = apps.get_model("expenses", "Transfer")
|
||||||
|
|
||||||
|
# Solo las patas que aún no pertenecen a ningún Transfer.
|
||||||
|
expenses_by_key = defaultdict(list)
|
||||||
|
for expense in Expense.objects.filter(
|
||||||
|
is_transfer=True, transfer_out__isnull=True, transfer_fee__isnull=True
|
||||||
|
):
|
||||||
|
expenses_by_key[(expense.owner_id, expense.amount, expense.date)].append(
|
||||||
|
expense
|
||||||
|
)
|
||||||
|
|
||||||
|
incomes_by_key = defaultdict(list)
|
||||||
|
for income in Income.objects.filter(is_transfer=True, transfer_in__isnull=True):
|
||||||
|
incomes_by_key[(income.owner_id, income.amount, income.date)].append(income)
|
||||||
|
|
||||||
|
for key, expenses in expenses_by_key.items():
|
||||||
|
incomes = incomes_by_key.get(key, [])
|
||||||
|
|
||||||
|
# Uno y solo uno de cada lado: cualquier otra cosa es ambigua.
|
||||||
|
if len(expenses) != 1 or len(incomes) != 1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
expense, income = expenses[0], incomes[0]
|
||||||
|
|
||||||
|
if expense.account_id == income.account_id:
|
||||||
|
continue
|
||||||
|
|
||||||
|
Transfer.objects.create(
|
||||||
|
owner_id=expense.owner_id,
|
||||||
|
date=expense.date,
|
||||||
|
amount=expense.amount,
|
||||||
|
from_account_id=expense.account_id,
|
||||||
|
to_account_id=income.account_id,
|
||||||
|
expense_leg=expense,
|
||||||
|
income_leg=income,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("expenses", "0014_category_is_system_transfer"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
# Sin marcha atrás: deshacer esto es deshacer 0014, que se lleva la tabla
|
||||||
|
# Transfer entera y deja las patas intactas, que es el estado de partida.
|
||||||
|
migrations.RunPython(link_legacy_transfers, migrations.RunPython.noop),
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue
Block a user