Migrar de EuroWin o Sage a Odoo: guia de migració per a distribució

Cas real Cymit Química: estratègia, mapatge de dades, ETL, cutover i go-live en migrar de EuroWin i Access a Odoo en una empresa de distribució amb més de dos milions de referències.

Per què migrar de EuroWin o Sage a Odoo en distribució

EuroWin i Sage són dos dels ERPs més implantats a les pimes espanyoles dels sectors de distribució, comerç i fabricació lleugera. Són eines que van resoldre molt bé els problemes dels anys noranta i dos mil: comptabilitat, facturació, comandes de compra i venda, gestió de magatzem. Però el 2026 han envellit d'una manera que no té solució de pedaç: la seva arquitectura impedeix la integració real amb plataformes de comerç electrònic, l'automatització de catàlegs, la visibilitat en temps real del negoci i l'escalabilitat que exigeixen les operatives modernes de distribució.

La migració que descric en aquesta guia no és teòrica. Vaig liderar personalment la migració de Cymit Química des de EuroWin + Microsoft Access + CRM Visual cap a Odoo quan era CEO de l'empresa. El resultat va ser un creixement de facturació de 2 M€ a 4 M€ i, finalment, l'adquisició de l'empresa pel Grup PALEX. El que segueix és la metodologia real que vaig fer servir, amb els problemes concrets que van aparèixer i com els vam resoldre.

Diagnòstic previ: per què moltes migracions fracassen

El fracàs més freqüent en migracions d'ERP no és tècnic: és de planificació. Els projectes que he vist fallar comparteixen patrons comuns:

  • Subestimar la qualitat de les dades d'origen: EuroWin i Sage emmagatzemen anys de dades introduïdes manualment, amb inconsistències, duplicats, clients mal classificats i productes amb referències trencades. Netejar aquestes dades porta més temps que la pròpia migració tècnica.
  • Intentar migrar-ho tot de cop sense pla de rollback: el «big bang» sense xarxa de seguretat és la recepta del desastre en empreses amb operativa diària que no pot parar.
  • No involucrar l'equip operatiu des de l'inici: els usuaris finals coneixen les particularitats del negoci que cap consultor extern descobrirà llegint la documentació. La seva aportació en el mapatge de dades és imprescindible.
  • Migrar dades històriques que ningú no farà servir: migrar 10 anys d'historial de moviments de magatzem té un cost alt i un valor qüestionable. Definir amb criteri de negoci quin historial és necessari estalvia setmanes de feina.

Estratègia de migració: big bang vs per fases

Big bang

La migració en big bang consisteix a migrar totes les dades i fer el tall a Odoo en una única data. El sistema antic es congela (no s'admeten més operacions), s'executa la migració completa i s'activa Odoo com a únic sistema operatiu.

Avantatges: no hi ha període de doble operació; la complexitat de mantenir dos sistemes sincronitzats desapareix el dia del tall. És més senzilla de gestionar operativament un cop executada.

Riscos: si alguna cosa falla el dia del tall (dades corruptes, integració que no funciona, usuaris que no saben operar el nou sistema), tota l'operativa s'atura. Requereix un pla de rollback clar i provat.

Quan és adequada: empreses de mida petita o mitjana (fins a ~30 usuaris) amb catàlegs de productes relativament acotats, on el risc operatiu d'una parada curta és assumible.

Migració per fases

La migració per fases activa mòduls d'Odoo de forma incremental, mantenint el sistema antic per a les àrees no migrades fins que cada fase està consolidada.

Un ordre típic per a una empresa de distribució:

  1. Fase 0 (preparació): configuració d'Odoo, mestres (clients, proveïdors, productes), configuració de comptabilitat. Operativa en paral·lel.
  2. Fase 1 (vendes i compres): comandes de venda i compra a Odoo; la facturació segueix al sistema antic temporalment o en paral·lel.
  3. Fase 2 (magatzem): gestió d'estoc i albarans a Odoo. L'inventari inicial es pren com a punt de referència.
  4. Fase 3 (comptabilitat): tancament comptable al sistema antic i obertura de saldos a Odoo. Facturació completa a Odoo.
  5. Fase 4 (tancament del sistema antic): historial migrat o arxivat en consulta, sistema antic desactivat.

Quan és adequada: empreses de mida més gran, operatives complexes amb moltes integracions, o quan l'equip necessita temps d'aprenentatge sense la pressió que el negoci ja depengui d'Odoo.

La decisió a Cymit

A Cymit Química vam optar per una aproximació híbrida: fases per a l'operativa principal (vendes, compres, magatzem) però amb data de tall definida i ferma per a la comptabilitat. La raó va ser que teníem tres sistemes desconnectats (EuroWin, Access, CRM Visual) i no es podia allargar indefinidament un període de doble operació en tres fronts simultanis. Definir fases però amb terminis concrets va ser el que va permetre completar la migració sense que es convertís en un projecte sense fi.

Mapatge de dades: de EuroWin i Sage a Odoo

Clients i contactes

EuroWin emmagatzema clients en taules pròpies amb camps específics del sistema que no tenen correspondència directa a Odoo. Els problemes més freqüents:

  • Duplicats: un mateix client pot tenir dues fitxes (una creada per l'equip de vendes, una altra pel de facturació) amb lleugeres variacions en el nom o en el NIF. La deduplicació és manual o semiautomàtica i requereix decisió humana.
  • Clients amb múltiples adreces: a EuroWin l'adreça és un camp del client; a Odoo el model permet múltiples contactes (matriu/fill) amb adreces diferents. Cal decidir com es mapeja aquesta estructura.
  • Classificacions i tarifes: les tarifes per client (descomptes, preus especials) s'han de migrar a les llistes de preus d'Odoo, que tenen una estructura més potent però també més complexa.

Mapatge orientatiu de camps de client:

Camp EuroWin / SageCamp Odoo (res.partner)Notes
Codi clientrefConservar com a referència interna
Nom fiscalnameNormalitzar majúscules/minúscules
NIF/CIFvatAfegir prefix ES si manca
Adreçastreet, city, zip, state_id, country_idNormalitzar usant el catàleg de municipis INE
Telèfonphone / mobileVerificar format E.164
EmailemailValidar sintaxi; descartar els no vàlids
Tarifa / descompteproperty_product_pricelistCrear llista de preus equivalent a Odoo
Forma de pagamentproperty_payment_term_idCrear condicions de pagament equivalents
Compte comptableproperty_account_receivable_idMapejar al pla de comptes d'Odoo

Productes i catàleg

El catàleg de productes és habitualment l'actiu més complex de migrar en empreses de distribució. A Cymit, amb més de dos milions de referències, va ser la feina de major volum del projecte. Els punts crítics:

  • Referència interna vs referència de proveïdor: EuroWin sol emmagatzemar la referència del proveïdor com a referència principal. Odoo separa la referència interna (default_code) de les referències de proveïdor (product.supplierinfo). Cal decidir què es converteix en què.
  • Categories i estructura de catàleg: la jerarquia de categories d'EuroWin rarament encaixa directament amb la que necessites a Odoo. És una oportunitat per redissenyar la taxonomia del catàleg.
  • Unitats de mesura: Odoo suporta múltiples UdM amb conversió; EuroWin i Sage tenen suport variable. Els productes venuts en caixes però emmagatzemats en unitats requereixen configuració específica.
  • Preus i tarifes: els preus de venda i cost a EuroWin s'han de mapejar a les pricelists d'Odoo, que funcionen de manera diferent (regles basades en categories, quantitats, dates).

Estoc inicial

L'inventari inicial és el punt de partida del magatzem a Odoo. Les opcions són:

  • Prendre l'estoc actual de l'ERP antic com a inventari inicial: es migra la quantitat en estoc de cada producte a Odoo mitjançant un ajust d'inventari. És el mètode més ràpid però assumeix que l'estoc del sistema antic és correcte.
  • Fer un recompte físic abans del tall: més laboriós però elimina les discrepàncies acumulades. Recomanat si hi ha motius per dubtar de la fiabilitat de l'estoc a EuroWin o Sage.

A Cymit vam fer un recompte selectiu: els productes d'alt valor o alta rotació es van recomptar físicament; la resta es va prendre del sistema amb un factor de correcció estimat. Les diferències es van regularitzar durant el primer mes d'operació a Odoo.

Comptabilitat i historial

La migració comptable és la més delicada i la que requereix més criteri de negoci. Les decisions clau són:

  • Data d'obertura: el saldo inicial a Odoo ha de quadrar amb el balanç de tancament del sistema antic. Habitualment es migra al tancament d'un exercici fiscal per simplificar la conciliació.
  • Historial de factures: les factures emeses abans de la data de tall no es migren com a documents Odoo (és molt costós i poc útil). Es mantenen al sistema antic en mode consulta. Només es migren els saldos pendents de cobrament/pagament (cartera d'efectes) com a apunts d'obertura.
  • Pla de comptes: el pla de comptes de EuroWin o Sage s'ha de mapejar al pla comptable espanyol a Odoo. Odoo inclou la localització espanyola (l10n_es) amb el PGC complet; la feina consisteix a mapejar els comptes del sistema antic als equivalents del PGC.

ETL: extracció, transformació i càrrega

Extracció des de EuroWin

EuroWin no té una API moderna. Les vies d'extracció són:

  1. Exportació a Excel/CSV des de la pròpia aplicació: la forma més senzilla per a volums petits. Limitada en flexibilitat i sense accés a totes les taules.
  2. Accés directe a la base de dades de EuroWin: EuroWin emmagatzema les seves dades en una base de dades SQL (SQL Server o similar, segons la versió). Amb accés de només lectura a aquesta BD, es poden extreure totes les dades amb SQL. Aquesta és la via recomanada per a migracions completes.

Exemple d'extracció de clients des de la BD de EuroWin (estructura aproximada, varia per versió):

-- Extraer clientes de EuroWin (SQL Server)
SELECT
    c.CodCliente        AS codigo_externo,
    c.RazonSocial       AS nombre,
    c.CIF               AS cif,
    c.Direccion         AS calle,
    c.CodPostal         AS cp,
    c.Poblacion         AS ciudad,
    c.Telefono          AS telefono,
    c.Email             AS email,
    c.CodFormaPago      AS forma_pago_codigo,
    c.CodTarifa         AS tarifa_codigo,
    c.Observaciones     AS notas_internas
FROM
    Clientes c
WHERE
    c.Activo = 1
ORDER BY
    c.CodCliente;

Neteja i deduplicació

El pas més lent i més crític del procés ETL és la neteja de dades. Un script de Python per a les tasques més comunes:

import pandas as pd
import re

# Cargar el CSV exportado de EuroWin
df = pd.read_csv('clientes_eurowin.csv', encoding='latin-1', sep=';')

# 1. Normalizar CIF: añadir prefijo ES si falta
def normalizar_cif(cif):
    if pd.isna(cif) or str(cif).strip() == '':
        return False
    cif = str(cif).strip().upper().replace(' ', '').replace('-', '')
    if not cif.startswith('ES'):
        cif = 'ES' + cif
    return cif

df['vat'] = df['cif'].apply(normalizar_cif)

# 2. Normalizar nombre: Title Case, quitar espacios dobles
df['name'] = df['nombre'].str.strip().str.title()
df['name'] = df['name'].str.replace(r'\s+', ' ', regex=True)

# 3. Validar emails
EMAIL_REGEX = re.compile(r'^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$')
df['email_valido'] = df['email'].apply(
    lambda x: str(x).strip().lower() if pd.notna(x) and EMAIL_REGEX.match(str(x).strip()) else False
)

# 4. Detectar duplicados por CIF (el identificador más fiable)
duplicados_cif = df[df.duplicated(subset=['vat'], keep=False) & (df['vat'] != False)]
print(f'Clientes con CIF duplicado: {len(duplicados_cif)}')
duplicados_cif.to_csv('revisar_duplicados_cif.csv', index=False)

# 5. Detectar duplicados por nombre (fuzzy: nombres muy similares)
# Requiere: pip install rapidfuzz
from rapidfuzz import fuzz
nombres = df['name'].dropna().unique().tolist()
posibles_duplicados = []
for i, n1 in enumerate(nombres):
    for n2 in nombres[i+1:]:
        if fuzz.ratio(n1, n2) > 85:
            posibles_duplicados.append({'nombre_1': n1, 'nombre_2': n2, 'similitud': fuzz.ratio(n1, n2)})

pd.DataFrame(posibles_duplicados).to_csv('revisar_duplicados_nombre.csv', index=False)
print(f'Pares de nombres con similitud >85%: {len(posibles_duplicados)}')

print('\nResumen:')
print(f'  Total clientes exportados: {len(df)}')
print(f'  Clientes con CIF válido: {(df['vat'] != False).sum()}')
print(f'  Clientes con email válido: {(df['email_valido'] != False).sum()}')

Càrrega a Odoo via API XML-RPC

Odoo disposa d'una API XML-RPC completa que permet crear i actualitzar registres de forma programàtica. És la via recomanada per a la càrrega de dades de migració (en lloc d'importacions CSV manuals, que són propenses a errors i no traçables):

import xmlrpc.client
import pandas as pd

# Conexión a Odoo
ODOO_URL = 'https://odoo.tudominio.com'
DB = 'odoo_produccion'
USER = 'admin@tudominio.com'
PASSWORD = 'la_password_del_admin'

common = xmlrpc.client.ServerProxy(f'{ODOO_URL}/xmlrpc/2/common')
uid = common.authenticate(DB, USER, PASSWORD, {})
models = xmlrpc.client.ServerProxy(f'{ODOO_URL}/xmlrpc/2/object')

def crear_cliente_odoo(row, pricelist_map, payment_term_map):
    '''Crea un cliente en Odoo desde una fila del DataFrame limpio.'''
    vals = {
        'name': row['name'],
        'customer_rank': 1,
        'ref': str(row['codigo_externo']),
        'street': row.get('calle', ''),
        'zip': str(row.get('cp', '')),
        'city': row.get('ciudad', ''),
        'country_id': 69,    # España — ID verificar en tu instancia
        'lang': 'es_ES',
    }
    if row['vat']:
        vals['vat'] = row['vat']
    if row['email_valido']:
        vals['email'] = row['email_valido']
    if row.get('telefono'):
        vals['phone'] = str(row['telefono'])
    # Mapear tarifa y forma de pago usando los diccionarios de mapeo
    tarifa_codigo = row.get('tarifa_codigo')
    if tarifa_codigo and tarifa_codigo in pricelist_map:
        vals['property_product_pricelist'] = pricelist_map[tarifa_codigo]
    pago_codigo = row.get('forma_pago_codigo')
    if pago_codigo and pago_codigo in payment_term_map:
        vals['property_payment_term_id'] = payment_term_map[pago_codigo]

    partner_id = models.execute_kw(
        DB, uid, PASSWORD,
        'res.partner', 'create', [vals]
    )
    return partner_id

# Ejecutar la carga con manejo de errores
df_limpio = pd.read_csv('clientes_listos_para_odoo.csv')
errores = []
ok = 0

for idx, row in df_limpio.iterrows():
    try:
        pid = crear_cliente_odoo(row, pricelist_map={}, payment_term_map={})
        ok += 1
        if ok % 100 == 0:
            print(f'Cargados {ok} clientes...')
    except Exception as e:
        errores.append({'fila': idx, 'codigo': row['codigo_externo'], 'error': str(e)})

print(f'\nCarga completada: {ok} clientes OK, {len(errores)} errores.')
pd.DataFrame(errores).to_csv('errores_carga_clientes.csv', index=False)

Validació i reconciliació

Carregar les dades no és el final. La validació és el pas que determina si la migració és realment correcta o si hi ha problemes que només apareixeran setmanes després en producció.

Les verificacions mínimes després de la càrrega:

  • Recompte de registres: el nombre de clients, productes i proveïdors a Odoo ha de coincidir amb el del sistema d'origen, menys els registres eliminats durant la neteja. Documentar la diferència i justificar-la.
  • Reconciliació de saldos comptables: el saldo total de comptes a cobrar a Odoo ha de quadrar amb el del sistema antic a la data de tall. Qualsevol diferència ha de tenir una explicació (apunt manual, diferència d'arrodoniment, etc.).
  • Verificació d'inventari: el valor total de l'inventari a Odoo ha de coincidir amb el del sistema antic. Mostreig de productes d'alt valor per verificar individualment.
  • Prova de cicle complet: crear una comanda de prova a Odoo de principi a fi (comanda → albarà → factura → cobrament) amb dades reals per verificar que el flux funciona correctament abans del go-live.
  • Validació amb usuaris clau: els responsables de vendes, magatzem i comptabilitat han de revisar les seves dades a Odoo abans del tall. Ells detectaran problemes que cap script automatitzat trobarà.

Pla de tall (cutover)

El cutover és el moment de màxim risc i màxima planificació. Un bon pla de tall té minut a minut el que passarà, qui l'executa i quina comprovació confirma que aquell pas s'ha fet correctament.

Setmana prèvia al tall

  • Congelar canvis al sistema antic (no es donen d'alta nous clients ni productes a EuroWin/Sage).
  • Executar la migració completa en entorn de preproducció per verificar que els scripts funcionen sense errors.
  • Formació final dels usuaris clau (responsables de cada àrea).
  • Preparar el pla de rollback: què fer si el dilluns al matí Odoo no funciona correctament.

El cap de setmana del tall

# Plan de corte — ejemplo Cymit Química (simplificado)

Viernes 18:00 — Cierre operativo en EuroWin
  - Verificar que no hay pedidos pendientes de procesar
  - Hacer dump final de EuroWin (backup completo)
  - Tomar inventario de stock final

Viernes 20:00 — Extracción de datos finales
  - Extraer clientes, productos, stock, saldos contables
  - Ejecutar scripts de limpieza y transformación
  - Generar ficheros de carga para Odoo

Sábado 08:00 — Carga en Odoo producción
  - Cargar maestros (clientes, proveedores, productos)
  - Ajuste de inventario inicial
  - Apertura de saldos contables
  - Verificar conteos y reconciliaciones

Sábado 14:00 — Validación con usuarios clave
  - Responsable de ventas verifica sus clientes y tarifas
  - Responsable de almacén verifica stock
  - Contable verifica saldos de apertura

Sábado 18:00 — Decisión GO / NO-GO
  - Si todo cuadra: GO (Odoo en producción el lunes)
  - Si hay problemas críticos: NO-GO (EuroWin sigue activo, analizar)

Domingo — Buffer para correcciones menores
  - Resolver incidencias detectadas el sábado
  - Preparar soporte reforzado para el lunes

Lunes 08:00 — Go-live
  - Odoo es el único sistema operativo
  - Soporte técnico disponible todo el día

Pla de rollback

El pla de rollback ha d'estar documentat i ser executable sense dependre del consultor de migració. Si el dilluns al matí hi ha un problema crític a Odoo que impedeix l'operativa, els passos han de ser clars:

  1. Comunicar a tot l'equip que s'activa el rollback.
  2. Desactivar l'accés dels usuaris a Odoo (perquè no generin dades que després siguin inconsistents).
  3. Reactivar EuroWin/Sage amb les dades del backup del divendres.
  4. Documentar tots els moviments que es van fer a Odoo abans del rollback per reproduir-los al sistema antic.
  5. Anàlisi de causa arrel del problema i pla de correcció abans del següent intent de cutover.

Formació i gestió del canvi

A Cymit, el major obstacle no va ser tècnic: va ser la resistència al canvi d'un equip que portava anys treballant amb EuroWin i coneixia les seves dreceres i limitacions. La formació no pot ser un PDF i una sessió de dues hores.

El que va funcionar:

  • Formació per rols, no per funcionalitats: en lloc d'ensenyar «això és Odoo», ensenyar «així processes una comanda de venda al teu nou sistema». Cada rol té un flux específic que cal entrenar fins que sigui automàtic.
  • Entorn de formació amb dades reals anonimitzades: els usuaris aprenen millor quan veuen els seus propis clients i productes, encara que estiguin anonimitzats. Un entorn de formació genèric no prepara per a la realitat.
  • Usuaris campió per àrea: identificar una persona de cada àrea (vendes, magatzem, comptabilitat) que es formi més en profunditat i sigui el primer punt de contacte per als seus companys. Això redueix dràsticament la dependència del suport extern.
  • Suport reforçat els primers 30 dies: el període immediatament posterior al go-live és on es concentra el 80% dels dubtes. Tenir suport disponible i ràpid durant aquell mes marca la diferència entre una migració que «va anar bé» i una que «va ser un desastre».

Riscos principals i com mitigar-los

RiscProbabilitatImpacteMitigació
Dades d'origen amb més duplicats i errors dels esperatsAltaAlt (retarda el projecte)Auditoria de dades les primeres setmanes, no a l'última hora
Rebuig de l'equip al canviMitjanaAlt (ús incorrecte del sistema)Involucrar l'equip des de la fase de disseny, no només a la formació
Pèrdua de dades en el tallBaixaCríticCòpies de seguretat verificades abans del cutover, pla de rollback provat
Integració amb altres eines que falla (botiga en línia, TPV, logística)MitjanaAltaInventariar totes les integracions a la fase de diagnòstic, no al final
El projecte s'allarga indefinidament (scope creep)AltaMitjà (cost)Definir abast tancat per a la migració base; millores en fases posteriors
Paralització per no poder accedir a l'historialMitjanaBaix-MitjàMantenir EuroWin/Sage en mode consulta durant 12 mesos després del tall

Lliçons apreses a Cymit

Cinc anys després del procés, i havent vist altres migracions des d'aleshores, les lliçons que portaria a qualsevol projecte similar són:

  1. La qualitat de les dades d'origen determina el 70% de l'èxit del projecte. Inverteix temps en auditar-les al principi, no al final. Cada problema de qualitat de dades que descobreixes en producció costa deu vegades més que haver-lo detectat abans.
  2. No migrïs el que no fas servir. L'historial de factures de fa 8 anys que ningú consulta pot quedar-se al sistema antic en mode arxiu. Migrar per completisme allarga el projecte sense aportar valor real.
  3. Defineix el criteri d'èxit abans de començar. «La migració està bé» és ambigu. «El saldo de comptes a cobrar quadra amb el balanç anterior amb una tolerància d'1€, els recomptes de clients i productes estan dins del 2% de variació justificada i s'ha processat amb èxit un cicle complet de venda-magatzem-facturació» és un criteri verificable.
  4. El dia del go-live no és el final: és el principi. Els primers 90 dies són el període de major risc i major necessitat de suport. Planifica recursos per a aquell període abans de començar el projecte.
  5. La plataforma que construeixes ha de poder ser adquirida. A Cymit, l'arquitectura neta a Odoo va ser part de l'argument de valoració en el procés de M&A amb PALEX. Si en el teu horitzó hi ha la possibilitat d'una transacció corporativa, la tecnologia és part del preu.

Estàs valorant migrar de EuroWin, Sage o un altre ERP legacy a Odoo?

Sol·licitar auditoria de migració gratuïta

Integrar IA a Odoo: lead scoring i models predictius amb Python
Guia tècnica completa per connectar models de machine learning a Odoo CRM: des del disseny del pipeline de dades fins al scoring en temps real d'oportunitats comercials