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:
102
scripts/odoo-test-data.py
Executable file
102
scripts/odoo-test-data.py
Executable file
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Script para crear datos de prueba en Odoo SKEEN"""
|
||||
|
||||
import xmlrpc.client
|
||||
|
||||
# Conexión a Odoo
|
||||
url = 'http://localhost:8069'
|
||||
db = 'skeen_odoo'
|
||||
username = 'admin'
|
||||
password = 'admin'
|
||||
|
||||
# Autenticación
|
||||
common = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/common')
|
||||
uid = common.authenticate(db, username, password, {})
|
||||
|
||||
if not uid:
|
||||
print("Error: No se pudo autenticar")
|
||||
exit(1)
|
||||
|
||||
print(f"Autenticado como uid={uid}")
|
||||
|
||||
models = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object')
|
||||
|
||||
# 1. Crear servicios
|
||||
servicios = [
|
||||
{'name': 'Consulta Dermatologica General', 'code': 'CONS-GEN', 'category': 'consulta', 'price': 800, 'duration_min': 30, 'description': 'Evaluación completa de la piel'},
|
||||
{'name': 'Consulta de Valoracion Gratuita', 'code': 'CONS-VAL', 'category': 'consulta', 'price': 0, 'duration_min': 15, 'description': 'Evaluación breve sin compromiso'},
|
||||
{'name': 'Tratamiento Facial para Acne', 'code': 'TRAT-ACN', 'category': 'tratamiento', 'price': 1500, 'duration_min': 60, 'description': 'Limpieza profunda y extracción'},
|
||||
{'name': 'Peel Quimico', 'code': 'PROC-PEEL', 'category': 'procedimiento', 'price': 1500, 'duration_min': 30, 'description': 'Exfoliación química para renovar piel'},
|
||||
{'name': 'Depilacion Laser', 'code': 'PROC-LAS', 'category': 'procedimiento', 'price': 500, 'duration_min': 15, 'description': 'Depilación laser por zona'},
|
||||
{'name': 'Tratamiento Anti-Edad', 'code': 'TRAT-ANTI', 'category': 'tratamiento', 'price': 2500, 'duration_min': 75, 'description': 'Microdermoabrasión y vitaminas'},
|
||||
]
|
||||
|
||||
for s in servicios:
|
||||
existing = models.execute_kw(db, uid, password, 'skeen.servicio', 'search', [[['code', '=', s['code']]]])
|
||||
if not existing:
|
||||
sid = models.execute_kw(db, uid, password, 'skeen.servicio', 'create', [s])
|
||||
print(f"Servicio creado: {s['name']} (ID: {sid})")
|
||||
else:
|
||||
print(f"Servicio ya existe: {s['name']}")
|
||||
|
||||
# 2. Crear pacientes
|
||||
pacientes = [
|
||||
{'name': 'Sofia Garcia', 'phone': '+526641234567', 'email': 'sofia@email.com', 'is_patient': True, 'source': 'whatsapp', 'blood_type': 'o+', 'allergies': 'Ninguna'},
|
||||
{'name': 'Maria Lopez', 'phone': '+526642345678', 'email': 'maria@email.com', 'is_patient': True, 'source': 'facebook', 'blood_type': 'a+', 'allergies': 'Penicilina'},
|
||||
{'name': 'Ana Martinez', 'phone': '+526643456789', 'email': 'ana@email.com', 'is_patient': True, 'source': 'instagram', 'blood_type': 'b+', 'allergies': 'Ninguna'},
|
||||
{'name': 'Carmen Ruiz', 'phone': '+526644567890', 'email': 'carmen@email.com', 'is_patient': True, 'source': 'google', 'blood_type': 'ab+', 'allergies': 'Látex'},
|
||||
{'name': 'Laura Hernandez', 'phone': '+526645678901', 'email': 'laura@email.com', 'is_patient': True, 'source': 'referral', 'blood_type': 'o-', 'allergies': 'Ninguna'},
|
||||
]
|
||||
|
||||
for p in pacientes:
|
||||
existing = models.execute_kw(db, uid, password, 'res.partner', 'search', [[['phone', '=', p['phone']]]])
|
||||
if not existing:
|
||||
pid = models.execute_kw(db, uid, password, 'res.partner', 'create', [p])
|
||||
print(f"Paciente creado: {p['name']} (ID: {pid})")
|
||||
else:
|
||||
print(f"Paciente ya existe: {p['name']}")
|
||||
|
||||
# 3. Crear citas
|
||||
from datetime import datetime, timedelta
|
||||
hoy = datetime.now().date()
|
||||
manana = hoy + timedelta(days=1)
|
||||
|
||||
# Obtener IDs de pacientes y servicios
|
||||
partner_ids = models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_patient', '=', True]]])
|
||||
servicio_ids = models.execute_kw(db, uid, password, 'skeen.servicio', 'search', [[]])
|
||||
|
||||
if partner_ids and servicio_ids:
|
||||
citas = [
|
||||
{'partner_id': partner_ids[0], 'servicio_id': servicio_ids[0], 'date': str(hoy), 'time': 9.0, 'state': 'confirmed'},
|
||||
{'partner_id': partner_ids[1], 'servicio_id': servicio_ids[2], 'date': str(hoy), 'time': 10.0, 'state': 'confirmed'},
|
||||
{'partner_id': partner_ids[2], 'servicio_id': servicio_ids[3], 'date': str(hoy), 'time': 11.5, 'state': 'pending'},
|
||||
{'partner_id': partner_ids[3], 'servicio_id': servicio_ids[4], 'date': str(manana), 'time': 14.0, 'state': 'confirmed'},
|
||||
{'partner_id': partner_ids[4], 'servicio_id': servicio_ids[1], 'date': str(manana), 'time': 16.0, 'state': 'confirmed'},
|
||||
]
|
||||
|
||||
for c in citas:
|
||||
existing = models.execute_kw(db, uid, password, 'skeen.cita', 'search', [
|
||||
[['partner_id', '=', c['partner_id']], ['date', '=', c['date']], ['time', '=', c['time']]]
|
||||
])
|
||||
if not existing:
|
||||
cid = models.execute_kw(db, uid, password, 'skeen.cita', 'create', [c])
|
||||
print(f"Cita creada: ID {cid}")
|
||||
else:
|
||||
print(f"Cita ya existe para fecha {c['date']} hora {c['time']}")
|
||||
|
||||
# 4. Crear monederos
|
||||
for pid in partner_ids:
|
||||
existing = models.execute_kw(db, uid, password, 'skeen.monedero', 'search', [[['partner_id', '=', pid]]])
|
||||
if not existing:
|
||||
mid = models.execute_kw(db, uid, password, 'skeen.monedero', 'create', [
|
||||
{'partner_id': pid, 'points': (pid % 10) * 100 + 50}
|
||||
])
|
||||
print(f"Monedero creado para paciente {pid}: {(pid % 10) * 100 + 50} pts")
|
||||
else:
|
||||
print(f"Monedero ya existe para paciente {pid}")
|
||||
|
||||
print("\n=== Datos de prueba creados exitosamente ===")
|
||||
print(f"Servicios: {len(models.execute_kw(db, uid, password, 'skeen.servicio', 'search', [[]]))}")
|
||||
print(f"Pacientes: {len(models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_patient', '=', True]]]))}")
|
||||
print(f"Citas: {len(models.execute_kw(db, uid, password, 'skeen.cita', 'search', [[]]))}")
|
||||
print(f"Monederos: {len(models.execute_kw(db, uid, password, 'skeen.monedero', 'search', [[]]))}")
|
||||
63
scripts/simular_meta_webhook.py
Normal file
63
scripts/simular_meta_webhook.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import hmac
|
||||
import hashlib
|
||||
import json
|
||||
import time
|
||||
import requests
|
||||
import sys
|
||||
|
||||
META_APP_SECRET = "skeen_meta_app_secret_2026_demo"
|
||||
PHONE_NUMBER_ID = "PENDING_PHONE_ID"
|
||||
WABA_ID = "PENDING_WABA_ID"
|
||||
|
||||
payload = {
|
||||
"object": "whatsapp_business_account",
|
||||
"entry": [
|
||||
{
|
||||
"id": WABA_ID,
|
||||
"changes": [
|
||||
{
|
||||
"value": {
|
||||
"messaging_product": "whatsapp",
|
||||
"metadata": {
|
||||
"display_phone_number": "1234567890",
|
||||
"phone_number_id": PHONE_NUMBER_ID,
|
||||
},
|
||||
"contacts": [
|
||||
{
|
||||
"profile": {"name": "Paciente Test"},
|
||||
"wa_id": "526641234568",
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"from": "526641234568",
|
||||
"id": f"wamid.test_{int(time.time())}",
|
||||
"timestamp": str(int(time.time())),
|
||||
"text": {"body": "Hola Sofia, que servicios tienen?"},
|
||||
"type": "text",
|
||||
}
|
||||
],
|
||||
},
|
||||
"field": "messages",
|
||||
}
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
raw_body = json.dumps(payload, separators=(",", ":"))
|
||||
signature = "sha256=" + hmac.new(
|
||||
META_APP_SECRET.encode(), raw_body.encode(), hashlib.sha256
|
||||
).hexdigest()
|
||||
|
||||
url = "http://localhost:3000/api/whatsapp/webhook"
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"x-hub-signature-256": signature,
|
||||
}
|
||||
|
||||
print("Enviando webhook simulado a", url)
|
||||
print("Body:", raw_body[:200], "...")
|
||||
response = requests.post(url, data=raw_body, headers=headers)
|
||||
print("Status:", response.status_code)
|
||||
print("Response:", response.text[:500])
|
||||
71
scripts/skeen-start-all.sh
Executable file
71
scripts/skeen-start-all.sh
Executable file
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
# SKEEN — Iniciar todos los servicios del ecosistema
|
||||
# Uso: ./skeen-start-all.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "=========================================="
|
||||
echo "Iniciando ecosistema SKEEN"
|
||||
echo "=========================================="
|
||||
|
||||
# 1. Supabase (PostgreSQL + Auth + Storage + Realtime)
|
||||
echo "[1/6] Iniciando Supabase self-hosted..."
|
||||
cd /root/skeen-supabase/docker
|
||||
docker compose up -d
|
||||
|
||||
# Esperar a que Supabase DB esté saludable
|
||||
echo "Esperando a que PostgreSQL esté listo..."
|
||||
for i in {1..30}; do
|
||||
if docker exec supabase-db pg_isready -U postgres > /dev/null 2>&1; then
|
||||
echo "PostgreSQL listo"
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# 2. Odoo 17
|
||||
echo "[2/6] Iniciando Odoo 17..."
|
||||
cd /root/skeen-odoo
|
||||
source /root/odoo-venv/bin/activate
|
||||
export SUPABASE_URL="http://localhost:8000"
|
||||
export SUPABASE_SERVICE_ROLE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UiLCJpYXQiOjE2NDE3NjkyMDAsImV4cCI6MTc5OTUzNTYwMH0.XA05Pgn-gkEKaZEaHYFc9DAyP45uNJdsl8DL9axUxbc"
|
||||
nohup ./odoo-bin -c odoo.conf --logfile=/tmp/odoo.log > /tmp/odoo_stdout.log 2>&1 &
|
||||
echo "Odoo iniciando con PID $!"
|
||||
|
||||
# 3. WACRM
|
||||
echo "[3/6] Iniciando WACRM..."
|
||||
cd /root/skeen-wacrm
|
||||
nohup npm start > /tmp/wacrm.log 2>&1 &
|
||||
echo "WACRM iniciando con PID $!"
|
||||
|
||||
# 4. Frontend React
|
||||
echo "[4/6] Iniciando Frontend React..."
|
||||
cd /root/skeen-frontend
|
||||
nohup npm run dev > /tmp/frontend.log 2>&1 &
|
||||
echo "Frontend iniciando con PID $!"
|
||||
|
||||
# 5. Hermes gateway
|
||||
echo "[5/7] Iniciando Hermes gateway..."
|
||||
cd /root
|
||||
HERMES_ACCEPT_HOOKS=1 nohup /root/hermes-venv/bin/hermes gateway run > /tmp/hermes-gateway.log 2>&1 &
|
||||
echo "Hermes gateway iniciando con PID $!"
|
||||
|
||||
# 6. Hermes serve (API/dashboard)
|
||||
echo "[6/7] Iniciando Hermes serve..."
|
||||
cd /root
|
||||
source /root/hermes-venv/bin/activate
|
||||
nohup hermes serve --host 0.0.0.0 --port 9119 --skip-build > /tmp/hermes-serve.log 2>&1 &
|
||||
echo "Hermes serve iniciando con PID $!"
|
||||
|
||||
# 6. Bridge webhook SKEEN
|
||||
echo "[7/7] Iniciando Bridge webhook SKEEN..."
|
||||
cd /root/skeen-roadmap-hermes/hermes
|
||||
nohup node webhook-bridge.js > /tmp/hermes-bridge.log 2>&1 &
|
||||
echo "Bridge iniciando con PID $!"
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Todos los servicios fueron iniciados"
|
||||
echo "Espera 15-30 segundos y verifica con:"
|
||||
echo " ss -tlnp | grep -E '3000|5173|8069|8000|8090|8644|8080|9119'"
|
||||
echo "=========================================="
|
||||
8
scripts/skeen-start-odoo.sh
Executable file
8
scripts/skeen-start-odoo.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
export SUPABASE_URL=http://192.168.10.114:8000
|
||||
export SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UiLCJpYXQiOjE2NDE3NjkyMDAsImV4cCI6MTc5OTUzNTYwMH0.XA05Pgn-gkEKaZEaHYFc9DAyP45uNJdsl8DL9axUxbc
|
||||
export WACRM_API_URL=http://localhost:3000
|
||||
export WACRM_API_KEY=wacrm_live_1m2xkLq9S75b8AWGB4a_tPPiFmJlJJ7wJHAPi9BZWcs
|
||||
export HERMES_BRIDGE_URL=http://localhost:8090
|
||||
cd /root/skeen-odoo
|
||||
exec /root/odoo-venv/bin/python ./odoo-bin -c odoo.conf --logfile=/tmp/odoo.log
|
||||
31
scripts/skeen-stop-all.sh
Executable file
31
scripts/skeen-stop-all.sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
# SKEEN — Detener todos los servicios del ecosistema
|
||||
# Uso: ./skeen-stop-all.sh
|
||||
|
||||
echo "=========================================="
|
||||
echo "Deteniendo ecosistema SKEEN"
|
||||
echo "=========================================="
|
||||
|
||||
# 1. Bridge webhook
|
||||
pgrep -f "webhook-bridge.js" | xargs -r kill -9 2>/dev/null || true
|
||||
|
||||
# 2. Hermes gateway
|
||||
pgrep -f "hermes gateway run" | xargs -r kill -9 2>/dev/null || true
|
||||
|
||||
# 3. Frontend (vite)
|
||||
pgrep -f "vite" | xargs -r kill -9 2>/dev/null || true
|
||||
|
||||
# 4. WACRM (next)
|
||||
pgrep -f "next-server" | xargs -r kill -9 2>/dev/null || true
|
||||
pgrep -f "next start" | xargs -r kill -9 2>/dev/null || true
|
||||
|
||||
# 5. Odoo
|
||||
pgrep -f "odoo-bin" | xargs -r kill -9 2>/dev/null || true
|
||||
|
||||
# 6. Supabase Docker
|
||||
cd /root/skeen-supabase/docker 2>/dev/null && docker compose down || echo "Supabase no estaba corriendo o docker no disponible"
|
||||
|
||||
echo "=========================================="
|
||||
echo "Servicios detenidos"
|
||||
echo "Verifica con: ss -tlnp | grep -E '3000|5173|8069|8000|8090|8644|8080'"
|
||||
echo "=========================================="
|
||||
Reference in New Issue
Block a user