Initial commit: SKEEN Derma Experts - Sistema Integral de Gestión Clínica
- Frontend React (SKEEN Brand) con Vite, TypeScript, Tailwind - Frontend Homenest (versión alternativa) - Módulos Odoo 17 custom (citas, pacientes, monedero, pagos, ventas, inventario, whatsapp) - WACRM fork (Next.js 16 + Supabase) - Hermes + Bridge + Skills (Qwen3.6 via Nan Builders) - Scripts de migración y operación - Documentación extensiva en docs/
This commit is contained in:
181
migracion/importar_pacientes_rapido.py
Normal file
181
migracion/importar_pacientes_rapido.py
Normal file
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Importador rápido de pacientes SKEEN a Odoo usando legacy_id como clave única."""
|
||||
import csv
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ODOO_PATH = Path('/root/skeen-odoo')
|
||||
sys.path.insert(0, str(ODOO_PATH))
|
||||
|
||||
import odoo
|
||||
from odoo import api, SUPERUSER_ID
|
||||
|
||||
DATA_DIR = Path('/root/migracion/datos')
|
||||
|
||||
|
||||
def normalize_bool(v):
|
||||
return str(v).lower() in ('1', 'true', 'si', 'sí')
|
||||
|
||||
|
||||
def main():
|
||||
odoo.tools.config.parse_config(['-c', '/root/skeen-odoo/odoo.conf'])
|
||||
db = odoo.sql_db.db_connect('skeen_odoo')
|
||||
cr = db.cursor()
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
|
||||
Partner = env['res.partner'].sudo()
|
||||
Tag = env['skeen.patient.tag'].sudo()
|
||||
Employee = env['hr.employee'].sudo()
|
||||
|
||||
# Cachés en memoria
|
||||
existing_legacy = {p.legacy_id: p.id for p in Partner.search([('legacy_id', '!=', False)]) if p.legacy_id}
|
||||
doctor_cache = {}
|
||||
tag_cache = {}
|
||||
|
||||
def get_or_create_doctor(name):
|
||||
name = ' '.join(str(name).split())
|
||||
if not name:
|
||||
return False
|
||||
if name in doctor_cache:
|
||||
return doctor_cache[name]
|
||||
clean = name.lower().replace('dra.', '').replace('dr.', '').replace('dr ', '').replace('dra ', '').strip()
|
||||
doctor = Employee.search(['|', ('name', 'ilike', name), ('name', 'ilike', clean)], limit=1)
|
||||
if not doctor:
|
||||
doctor = Employee.create({'name': name})
|
||||
doctor_cache[name] = doctor
|
||||
return doctor
|
||||
|
||||
def get_tag(name):
|
||||
if name in tag_cache:
|
||||
return tag_cache[name]
|
||||
tag = Tag.search([('name', '=', name)], limit=1)
|
||||
if not tag:
|
||||
tag = Tag.create({'name': name})
|
||||
tag_cache[name] = tag.id
|
||||
return tag.id
|
||||
|
||||
rows = []
|
||||
with open(DATA_DIR / 'pacientes.csv', newline='', encoding='utf-8') as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
rows.append(row)
|
||||
|
||||
print(f'Importando {len(rows)} pacientes...')
|
||||
count = 0
|
||||
skipped = 0
|
||||
batch = []
|
||||
BATCH_SIZE = 500
|
||||
|
||||
for row in rows:
|
||||
legacy_id = (row.get('legacy_id') or '').strip()
|
||||
name = ' '.join(filter(None, [
|
||||
row.get('nombre', ''),
|
||||
row.get('apellido_paterno', ''),
|
||||
row.get('apellido_materno', '')
|
||||
])).strip()
|
||||
phone = (row.get('telefono') or '').strip()
|
||||
if not name or not phone:
|
||||
skipped += 1
|
||||
continue
|
||||
if legacy_id and legacy_id in existing_legacy:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
vals = {
|
||||
'name': name,
|
||||
'phone': phone,
|
||||
'email': row.get('email', ''),
|
||||
'is_patient': True,
|
||||
'source': 'other',
|
||||
'is_vip': normalize_bool(row.get('vip')),
|
||||
}
|
||||
if legacy_id:
|
||||
vals['legacy_id'] = legacy_id
|
||||
|
||||
if row.get('fecha_nacimiento'):
|
||||
vals['birth_date'] = row.get('fecha_nacimiento')
|
||||
if row.get('sexo'):
|
||||
vals['gender'] = row.get('sexo')
|
||||
|
||||
# Datos personales
|
||||
if row.get('lugar_nacimiento'):
|
||||
vals['birthplace'] = row.get('lugar_nacimiento')
|
||||
if row.get('empleo'):
|
||||
vals['occupation'] = row.get('empleo')
|
||||
if row.get('estado_civil'):
|
||||
vals['marital_status'] = row.get('estado_civil')
|
||||
if row.get('contacto_emergencia'):
|
||||
vals['emergency_contact'] = row.get('contacto_emergencia')
|
||||
if row.get('telefono_emergencia'):
|
||||
vals['emergency_phone'] = row.get('telefono_emergencia')
|
||||
if row.get('telefono_casa'):
|
||||
vals['home_phone'] = row.get('telefono_casa')
|
||||
if row.get('direccion'):
|
||||
vals['address_notes'] = row.get('direccion')
|
||||
if row.get('recomendado_por'):
|
||||
vals['referred_by'] = row.get('recomendado_por')
|
||||
if row.get('comentarios'):
|
||||
vals['patient_comments'] = row.get('comentarios')
|
||||
|
||||
# Historia clínica
|
||||
try:
|
||||
vals['children_count'] = int(row.get('hijos', 0) or 0)
|
||||
except Exception:
|
||||
vals['children_count'] = 0
|
||||
vals['is_pregnant'] = normalize_bool(row.get('embarazada'))
|
||||
vals['is_breastfeeding'] = normalize_bool(row.get('lactancia'))
|
||||
vals['uses_contraceptives'] = normalize_bool(row.get('anticonceptivos'))
|
||||
vals['kidney_problems'] = normalize_bool(row.get('problemas_rinon'))
|
||||
vals['back_pain'] = normalize_bool(row.get('problemas_espalda'))
|
||||
vals['heart_disease'] = normalize_bool(row.get('problemas_cardiacos'))
|
||||
vals['respiratory_problems'] = normalize_bool(row.get('problemas_respiratorios'))
|
||||
vals['blood_pressure'] = normalize_bool(row.get('alta_presion')) or normalize_bool(row.get('baja_presion'))
|
||||
vals['diabetes'] = normalize_bool(row.get('diabetes'))
|
||||
vals['thyroid'] = normalize_bool(row.get('hipertiroidismo')) or normalize_bool(row.get('hipotiroidismo'))
|
||||
vals['colitis'] = normalize_bool(row.get('colitis'))
|
||||
vals['constipation'] = normalize_bool(row.get('estrenimiento'))
|
||||
vals['liver_problems'] = normalize_bool(row.get('problemas_higado'))
|
||||
vals['surgeries'] = normalize_bool(row.get('cirugias'))
|
||||
vals['varicose_veins'] = normalize_bool(row.get('varices'))
|
||||
vals['migraine'] = normalize_bool(row.get('migrana'))
|
||||
vals['faints_with_needles'] = normalize_bool(row.get('desmaya_agujas'))
|
||||
if row.get('alergias'):
|
||||
vals['allergies'] = row.get('alergias')
|
||||
if row.get('medicamentos'):
|
||||
vals['current_medication'] = row.get('medicamentos')
|
||||
if row.get('tratamientos_previos'):
|
||||
vals['medical_history'] = row.get('tratamientos_previos')
|
||||
|
||||
medico = get_or_create_doctor(row.get('medico_principal', ''))
|
||||
if medico:
|
||||
vals['primary_doctor_id'] = medico.id
|
||||
|
||||
etiquetas = row.get('etiquetas', '').strip()
|
||||
if etiquetas:
|
||||
tag_ids = [get_tag(t) for t in etiquetas.split(',') if t.strip()]
|
||||
vals['tag_ids'] = [(6, 0, tag_ids)]
|
||||
|
||||
batch.append(vals)
|
||||
if legacy_id:
|
||||
existing_legacy[legacy_id] = True
|
||||
|
||||
if len(batch) >= BATCH_SIZE:
|
||||
Partner.create(batch)
|
||||
count += len(batch)
|
||||
batch = []
|
||||
cr.commit()
|
||||
print(f' {count} pacientes creados')
|
||||
|
||||
if batch:
|
||||
Partner.create(batch)
|
||||
count += len(batch)
|
||||
cr.commit()
|
||||
|
||||
cr.commit()
|
||||
cr.close()
|
||||
print(f'Importación completada: {count} pacientes creados, {skipped} omitidos')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user