| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- import logging
- from django.utils.timezone import make_aware
- from decimal import Decimal
- from django.core.management.base import BaseCommand
- from datetime import datetime
- from django.utils.dateparse import parse_datetime
- import json
- import os
- from finanzas.models import Cuenta, Movimiento, Categoria
- from reymotausers.models import ReyMotaUser
- logger = logging.getLogger('importar_movimientos_externos')
- handler = logging.FileHandler('importar_movimientos.log')
- formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
- handler.setFormatter(formatter)
- logger.addHandler(handler)
- logger.setLevel(logging.INFO)
- class Command(BaseCommand):
- help = 'Importa movimientos externos desde un archivo JSON'
- def add_arguments(self, parser):
- parser.add_argument('archivo_json', type=str)
- def handle(self, *args, **options):
- ruta = options['archivo_json']
- if not os.path.exists(ruta):
- self.stdout.write(self.style.ERROR(f'Archivo no encontrado: {ruta}'))
- return
- with open(ruta, 'r', encoding='utf-8') as f:
- datos = json.load(f)
- for registro in datos:
- try:
- user = ReyMotaUser.objects.get(id=registro['user_id'])
- except ReyMotaUser.DoesNotExist:
- logger.warning(f"Usuario con id {registro['user_id']} no encontrado. Movimiento omitido.")
- continue
- nombre_origen = registro['source_name']
- nombre_destino = registro['destination_name']
- monto_raw = str(registro['amount']).replace(',', '.')
- try:
- monto = abs(Decimal(monto_raw))
- except:
- logger.warning(f"Monto inválido: {registro['amount']}")
- continue
- if nombre_origen == nombre_destino:
- logger.info(f"Movimiento con cuentas iguales omitido: {nombre_origen}")
- continue
- cuenta_origen, _ = Cuenta.objects.get_or_create(nombre=nombre_origen, usuario=user, defaults={'tipo': 'gasto'})
- cuenta_destino, _ = Cuenta.objects.get_or_create(nombre=nombre_destino, usuario=user, defaults={'tipo': 'ingreso'})
- fecha = make_aware(datetime.fromisoformat(registro['date'][:19]))
- descripcion = registro.get('description', '')
- # Detección de duplicado
- duplicado = Movimiento.objects.filter(
- usuario=user,
- cuenta_origen=cuenta_origen,
- cuenta_destino=cuenta_destino,
- monto=monto,
- fecha=fecha,
- descripcion=descripcion
- ).exists()
- if duplicado:
- logger.info(f"Duplicado omitido: {descripcion} - {monto} ({fecha})")
- continue
- mov = Movimiento.objects.create(
- usuario=user,
- cuenta_origen=cuenta_origen,
- cuenta_destino=cuenta_destino,
- monto=monto,
- fecha=fecha,
- descripcion=descripcion
- )
- if cat := registro.get('category'):
- categoria, _ = Categoria.objects.get_or_create(nombre=cat)
- mov.categoria = categoria
- mov.save()
- try:
- cuenta_origen.saldo -= monto
- cuenta_origen.save()
- except:
- logger.warning(f"Monto inválido: {registro['amount']} {registro['journal_id']}")
- continue
- try:
- cuenta_destino.saldo += monto
- cuenta_destino.save()
- except:
- logger.warning(f"Monto inválido: {registro['amount']}")
- continue
- logger.info(f"Movimiento importado: {descripcion} - {monto} ({fecha})")
- self.stdout.write(self.style.SUCCESS('Importación finalizada. Ver "importar_movimientos.log" para detalles.'))
|