# Metabase Actions — Alta de Piezas e Intercambios ## Requisitos - Metabase v0.44+ (Open Source o Pro) - Actions habilitadas en Admin → Settings - Database con "Model actions" activado --- ## 1. Configuración Inicial ### 1.1 Habilitar Actions 1. Ir a **Admin** → **Settings** 2. Buscar **"Enable Actions"** → Activar 3. Ir a **Admin** → **Databases** → Click en `nexus_autoparts` 4. Activar **"Model actions"** ### 1.2 Crear Modelos Base En Metabase, un **Modelo** es una pregunta (query) guardada como tabla virtual. Los Actions se vinculan a Modelos. **Modelo 1: Piezas OEM** → New → SQL Query: ```sql SELECT p.id_part, p.oem_part_number, p.name_part, p.name_es, pg.name_part_group AS grupo, pc.name_part_category AS categoria, p.description, p.description_es, p.weight_kg, mat.name_material AS material FROM parts p JOIN part_groups pg ON p.group_id = pg.id_part_group JOIN part_categories pc ON pg.category_id = pc.id_part_category LEFT JOIN materials mat ON p.id_material = mat.id_material ORDER BY p.oem_part_number ``` Guardar → Click ⋯ → **Turn into a model** → Nombrar: `Piezas OEM` **Modelo 2: Fitments** → New → SQL Query: ```sql SELECT vp.id_vehicle_part, b.name_brand AS marca, m.name_model AS modelo, y.year_car AS año, e.name_engine AS motor, p.oem_part_number, p.name_part AS pieza, vp.quantity_required AS cantidad, pp.name_position_part AS posicion, vp.fitment_notes AS notas FROM vehicle_parts vp JOIN model_year_engine mye ON vp.model_year_engine_id = mye.id_mye JOIN models m ON mye.model_id = m.id_model JOIN brands b ON m.brand_id = b.id_brand JOIN years y ON mye.year_id = y.id_year JOIN engines e ON mye.engine_id = e.id_engine JOIN parts p ON vp.part_id = p.id_part LEFT JOIN position_part pp ON vp.id_position_part = pp.id_position_part ORDER BY b.name_brand, m.name_model, y.year_car ``` Guardar → **Turn into a model** → Nombrar: `Fitments` **Modelo 3: Aftermarket** → New → SQL Query: ```sql SELECT ap.id_aftermarket_parts, p.oem_part_number AS oem_ref, p.name_part AS pieza_oem, mfr.name_manufacture AS fabricante, ap.part_number AS numero_aftermarket, ap.name_aftermarket_parts AS nombre, ap.name_es AS nombre_es, qt.name_quality AS calidad, ap.price_usd AS precio_usd, ap.warranty_months AS garantia_meses FROM aftermarket_parts ap JOIN parts p ON ap.oem_part_id = p.id_part JOIN manufacturers mfr ON ap.manufacturer_id = mfr.id_manufacture LEFT JOIN quality_tier qt ON ap.id_quality_tier = qt.id_quality_tier ORDER BY p.oem_part_number, mfr.name_manufacture ``` Guardar → **Turn into a model** → Nombrar: `Aftermarket` **Modelo 4: Cross-References** → New → SQL Query: ```sql SELECT pcr.id_part_cross_ref, p.oem_part_number AS oem_ref, p.name_part AS pieza, pcr.cross_reference_number AS numero_cruzado, rt.name_ref_type AS tipo_referencia, pcr.source_ref AS fuente, pcr.notes AS notas FROM part_cross_references pcr JOIN parts p ON pcr.part_id = p.id_part LEFT JOIN reference_type rt ON pcr.id_ref_type = rt.id_ref_type ORDER BY p.oem_part_number, rt.name_ref_type ``` Guardar → **Turn into a model** → Nombrar: `Cross-References` --- ## 2. Crear Actions (Formularios de Alta) Para cada Modelo, crear Actions que permiten insertar datos. ### Action 1: Nueva Pieza OEM 1. Abrir el modelo **Piezas OEM** 2. Click **⋯** → **Info** → **Actions** → **New action** 3. Nombrar: `Alta de Pieza OEM` 4. Pegar este SQL: ```sql INSERT INTO parts ( oem_part_number, name_part, name_es, group_id, description, description_es, weight_kg, id_material ) VALUES ( {{oem_part_number}}, {{name_part}}, {{name_es}}, {{group_id}}, {{description}}, {{description_es}}, {{weight_kg}}, {{id_material}} ) ``` 5. Configurar campos del formulario: | Variable | Label | Tipo | Requerido | |----------|-------|------|-----------| | `oem_part_number` | Número OEM | string | Si | | `name_part` | Nombre (EN) | string | Si | | `name_es` | Nombre (ES) | string | No | | `group_id` | ID Grupo | number | Si | | `description` | Descripción (EN) | string (long) | No | | `description_es` | Descripción (ES) | string (long) | No | | `weight_kg` | Peso (kg) | number | No | | `id_material` | ID Material | number | No | 6. Click **Save** > **Tip:** Para que el usuario no tenga que memorizar `group_id`, crea una pregunta > auxiliar con los grupos disponibles: > ```sql > SELECT pg.id_part_group AS id, pg.name_part_group AS grupo, > pc.name_part_category AS categoria > FROM part_groups pg > JOIN part_categories pc ON pg.category_id = pc.id_part_category > ORDER BY pc.display_order, pg.display_order > ``` --- ### Action 2: Nuevo Fitment (vincular pieza a vehículo) 1. Abrir el modelo **Fitments** 2. **New action** → Nombrar: `Alta de Fitment` 3. SQL: ```sql INSERT INTO vehicle_parts ( model_year_engine_id, part_id, quantity_required, id_position_part, fitment_notes ) VALUES ( {{model_year_engine_id}}, {{part_id}}, {{quantity_required}}, {{id_position_part}}, {{fitment_notes}} ) ``` | Variable | Label | Tipo | Requerido | Default | |----------|-------|------|-----------|---------| | `model_year_engine_id` | ID Vehículo (MYE) | number | Si | — | | `part_id` | ID Pieza | number | Si | — | | `quantity_required` | Cantidad | number | No | 1 | | `id_position_part` | Posición (1=front, 2=rear) | number | No | — | | `fitment_notes` | Notas | string | No | — | > **Tip:** Para encontrar el `model_year_engine_id`, crea esta pregunta auxiliar: > ```sql > SELECT mye.id_mye AS id, b.name_brand AS marca, > m.name_model AS modelo, y.year_car AS año, e.name_engine AS motor > FROM model_year_engine mye > JOIN models m ON mye.model_id = m.id_model > JOIN brands b ON m.brand_id = b.id_brand > JOIN years y ON mye.year_id = y.id_year > JOIN engines e ON mye.engine_id = e.id_engine > WHERE b.name_brand ILIKE {{'%' || marca || '%'}} > AND m.name_model ILIKE {{'%' || modelo || '%'}} > ORDER BY b.name_brand, m.name_model, y.year_car > ``` --- ### Action 3: Fitment Masivo (una pieza → varios vehículos) 1. En el modelo **Fitments** → **New action** 2. Nombrar: `Fitment Masivo por Marca/Modelo/Años` 3. SQL: ```sql INSERT INTO vehicle_parts (model_year_engine_id, part_id, quantity_required, id_position_part) SELECT mye.id_mye, {{part_id}}, {{quantity_required}}, {{id_position_part}} FROM model_year_engine mye JOIN models m ON mye.model_id = m.id_model JOIN brands b ON m.brand_id = b.id_brand JOIN years y ON mye.year_id = y.id_year WHERE b.name_brand ILIKE {{marca}} AND m.name_model ILIKE {{modelo}} AND y.year_car BETWEEN {{year_from}} AND {{year_to}} ON CONFLICT DO NOTHING ``` | Variable | Label | Tipo | Requerido | |----------|-------|------|-----------| | `part_id` | ID Pieza | number | Si | | `marca` | Marca (ej: TOYOTA) | string | Si | | `modelo` | Modelo (ej: Camry) | string | Si | | `year_from` | Año desde | number | Si | | `year_to` | Año hasta | number | Si | | `quantity_required` | Cantidad | number | Si | | `id_position_part` | Posición (1=front, 2=rear, vacío=N/A) | number | No | --- ### Action 4: Nueva Pieza Aftermarket 1. En el modelo **Aftermarket** → **New action** 2. Nombrar: `Alta de Pieza Aftermarket` 3. SQL: ```sql INSERT INTO aftermarket_parts ( oem_part_id, manufacturer_id, part_number, name_aftermarket_parts, name_es, id_quality_tier, price_usd, warranty_months ) VALUES ( {{oem_part_id}}, {{manufacturer_id}}, {{part_number}}, {{name_aftermarket_parts}}, {{name_es}}, {{id_quality_tier}}, {{price_usd}}, {{warranty_months}} ) ``` | Variable | Label | Tipo | Requerido | |----------|-------|------|-----------| | `oem_part_id` | ID Pieza OEM | number | Si | | `manufacturer_id` | ID Fabricante | number | Si | | `part_number` | Número Aftermarket | string | Si | | `name_aftermarket_parts` | Nombre (EN) | string | No | | `name_es` | Nombre (ES) | string | No | | `id_quality_tier` | Calidad (1=economy, 2=oem, 3=premium, 4=standard) | number | No | | `price_usd` | Precio USD | number | No | | `warranty_months` | Garantía (meses) | number | No | > **Tip:** Pregunta auxiliar para fabricantes: > ```sql > SELECT id_manufacture AS id, name_manufacture AS fabricante > FROM manufacturers ORDER BY name_manufacture > ``` --- ### Action 5: Nueva Cross-Reference 1. En el modelo **Cross-References** → **New action** 2. Nombrar: `Alta de Cross-Reference` 3. SQL: ```sql INSERT INTO part_cross_references ( part_id, cross_reference_number, id_ref_type, source_ref, notes ) VALUES ( {{part_id}}, {{cross_reference_number}}, {{id_ref_type}}, {{source_ref}}, {{notes}} ) ``` | Variable | Label | Tipo | Requerido | |----------|-------|------|-----------| | `part_id` | ID Pieza OEM | number | Si | | `cross_reference_number` | Número de Referencia | string | Si | | `id_ref_type` | Tipo (1=competitor, 2=interchange, 3=oem_alternate, 4=supersession) | number | No | | `source_ref` | Fuente | string | No | | `notes` | Notas | string | No | --- ## 3. Dashboard de Carga de Datos Crear un **Dashboard** que agrupe todo el flujo de carga: 1. **New** → **Dashboard** → Nombrar: `Panel de Carga de Datos` 2. Agregar estas tarjetas: ### Fila 1: Consulta rápida - **Buscar Pieza** (pregunta con filtro `{{oem_number}}`) - **Buscar Vehículo** (pregunta con filtros `{{marca}}`, `{{modelo}}`) ### Fila 2: Botones de Actions - **+ Nueva Pieza OEM** → Action 1 - **+ Nuevo Fitment** → Action 2 - **+ Fitment Masivo** → Action 3 - **+ Aftermarket** → Action 4 - **+ Cross-Reference** → Action 5 ### Fila 3: Referencias - **Tabla de Grupos** (grupos con IDs para referencia) - **Tabla de Fabricantes** (fabricantes con IDs) - **Estadísticas** (conteos actuales) ### Fila 4: Últimos registros - **Últimas piezas cargadas**: ```sql SELECT oem_part_number, name_part, name_es, created_at FROM parts ORDER BY created_at DESC LIMIT 10 ``` - **Últimos fitments**: ```sql SELECT b.name_brand, m.name_model, y.year_car, p.oem_part_number, vp.created_at FROM vehicle_parts vp JOIN model_year_engine mye ON vp.model_year_engine_id = mye.id_mye JOIN models m ON mye.model_id = m.id_model JOIN brands b ON m.brand_id = b.id_brand JOIN years y ON mye.year_id = y.id_year JOIN parts p ON vp.part_id = p.id_part ORDER BY vp.created_at DESC LIMIT 10 ``` --- ## 4. Flujo de Trabajo Recomendado ### Para cargar una pieza nueva con todo su contexto: ``` 1. Abrir "Panel de Carga de Datos" 2. Click [+ Nueva Pieza OEM] → Llenar: OEM#, Nombre, Grupo, Descripción → Submit → Anotar el ID generado 3. Click [+ Fitment Masivo] → Ingresar: ID pieza, Marca, Modelo, Rango de años → Submit → La pieza queda vinculada a todos los vehículos 4. Click [+ Aftermarket] (repetir por cada fabricante) → Ingresar: ID pieza OEM, ID fabricante, # aftermarket, precio → Submit 5. Click [+ Cross-Reference] (repetir por cada referencia) → Ingresar: ID pieza, # referencia, tipo → Submit 6. Verificar en "Últimos registros" que todo se cargó ``` --- ## 5. Preguntas Auxiliares Importantes Guardar estas como preguntas para tener a mano durante la carga: ### Buscar pieza por número ```sql SELECT id_part, oem_part_number, name_part, name_es FROM parts WHERE oem_part_number ILIKE {{'%' || numero || '%'}} OR name_part ILIKE {{'%' || numero || '%'}} ORDER BY oem_part_number LIMIT 50 ``` ### Buscar vehículo por marca/modelo ```sql SELECT mye.id_mye, b.name_brand, m.name_model, y.year_car, e.name_engine FROM model_year_engine mye JOIN models m ON mye.model_id = m.id_model JOIN brands b ON m.brand_id = b.id_brand JOIN years y ON mye.year_id = y.id_year JOIN engines e ON mye.engine_id = e.id_engine WHERE b.name_brand ILIKE {{'%' || marca || '%'}} AND m.name_model ILIKE {{'%' || modelo || '%'}} ORDER BY y.year_car DESC LIMIT 100 ``` ### Catálogo de grupos (referencia para group_id) ```sql SELECT pg.id_part_group AS id, pg.name_part_group AS grupo, pc.name_part_category AS categoria FROM part_groups pg JOIN part_categories pc ON pg.category_id = pc.id_part_category ORDER BY pc.display_order, pg.display_order ``` ### Catálogo de fabricantes (referencia para manufacturer_id) ```sql SELECT m.id_manufacture AS id, m.name_manufacture AS fabricante, mt.name_type_manu AS tipo, qt.name_quality AS calidad FROM manufacturers m LEFT JOIN manufacture_type mt ON m.id_type_manu = mt.id_type_manu LEFT JOIN quality_tier qt ON m.id_quality_tier = qt.id_quality_tier ORDER BY m.name_manufacture ``` --- ## 6. IDs de Referencia Rápida ### Calidad (`id_quality_tier`) | ID | Valor | |----|-------| | 1 | economy | | 2 | oem | | 3 | premium | | 4 | standard | ### Tipo de referencia (`id_ref_type`) | ID | Valor | Uso | |----|-------|-----| | 1 | competitor | Número de competidor equivalente | | 2 | interchange | Intercambio directo compatible | | 3 | oem_alternate | Número OEM alterno | | 4 | supersession | Pieza que esta reemplaza | ### Posición (`id_position_part`) | ID | Valor | |----|-------| | 1 | front | | 2 | rear | ### Tipo de fabricante (`id_type_manu`) | ID | Valor | |----|-------| | 1 | aftermarket | | 2 | oem |