Algoritmo Recursivo de Calificación T-MEC

Sprint 10 — Cómo se evalúan BOMs multi-nivel y materiales intermedios

El concepto en una frase

Un material intermedio es un subensamble que el productor declara explícitamente como tal: si cumple su propia regla de origen, todo su valor cuenta como originario. Si no cumple, el algoritmo se "cae" a evaluar sus componentes individuales.

¿Por qué importa? Esta elección del productor puede ser la diferencia entre que un producto califique como originario T-MEC o no. En el demo del 26-may-2026, declarar el motor de arranque como material intermedio fue lo que permitió que el motor completo cumpliera VCR 75%.

Flujo del algoritmo

El algoritmo se ejecuta recursivamente, una vez por cada nodo del BOM — desde las hojas hasta el producto raíz. Para cada nodo decide cuánto valor aporta como originario al nodo padre. El resultado final es el VCR del producto completo.

Hay tres caminos posibles según cómo se haya declarado el componente en el BOM: (1) hoja terminal — se evalúa su origen y listo; (2) subensamble común — se desarma y cada hijo cuenta individualmente; (3) material intermedio — se evalúa contra su propia regla T-MEC, y según si cumple o no, se trata como bloque originario o se desarma.

flowchart TD
    Start(["📦 Nodo del BOM
componente o subensamble"]) Start --> Q1{"¿Es hoja?
sourcing_type = PURCHASED
o sin hijos en el BOM
"} Q1 -->|Sí| Leaf["LEAF — Caso 1
Componente terminal.
Origen por país / certificado / manual.
Aporta su valor al padre con ese origen.
"] Q1 -->|No| Q2{"¿El productor declaró
material intermedio?
is_intermediate_material = true"} Q2 -->|No| SubA["SUBENSAMBLE COMÚN — Caso 2
Material propio sin regla.
Cada hijo aporta al padre
con su origen individual.
"] Q2 -->|Sí| Inter["MATERIAL INTERMEDIO — Caso 3
Tiene regla de origen propia
(Anexo 4-B).
Buscarla y evaluarla.
"] Inter --> Q3{"¿Cumple su
regla T-MEC?
VCR, brinco arancelario,
o ambos según rule_type
"} Q3 -->|Sí| Whole["WHOLE_ORIGINATING
Todo el subensamble cuenta
como originario al padre,
sin importar composición interna.
"] Q3 -->|No| Drill["DRILL_DOWN
El subensamble no cuenta como bloque.
Sus hijos aportan al padre
individualmente con sus orígenes.
"] classDef leafNode fill:#f3f4f6,stroke:#6b7280,color:#111827,stroke-width:1.5px classDef commonNode fill:#fef3c7,stroke:#c2410c,color:#111827,stroke-width:1.5px classDef interNode fill:#dbeafe,stroke:#2563eb,color:#111827,stroke-width:1.5px classDef passNode fill:#dcfce7,stroke:#15803d,color:#111827,stroke-width:1.5px classDef failNode fill:#fee2e2,stroke:#b91c1c,color:#111827,stroke-width:1.5px classDef startNode fill:#ffffff,stroke:#111827,color:#111827,stroke-width:1.5px class Start startNode class Leaf leafNode class SubA commonNode class Inter interNode class Whole passNode class Drill failNode
Cómo leer los nombres internos:
  • LEAF = el nodo no se desarma, se evalúa como pieza simple.
  • WHOLE_ORIGINATING = el subensamble entero (su valor total) suma como originario al padre.
  • DRILL_DOWN = el subensamble se "desarma" y son sus hijos los que aportan al padre.

Tipos de regla T-MEC y cuándo se cumplen

rule_typeSignificadoCumple si...
CC / CTH / CTSHSólo cambio arancelarioTodos los hijos no originarios cambian de capítulo / partida / subpartida
VCRSólo Valor de Contenido RegionalSub-VCR del subensamble ≥ umbral de la regla
BOTH EITHEREl productor eligeBrinco O VCR (basta con uno)
MIXEDAmbos exigidosBrinco Y VCR (ambos)

Ejemplos prácticos

Motor completo con motor de arranque como material intermedio

Producto: Motor completo 8407.32 — destino PASSENGER — VCR umbral 75%

Componente Valor Origen
Motor de arranque 8511.40 $548 Intermedio INTERNAL
Carcasa 8511.90 $100 MEX Originaria
Bobina 8511.90 $50 CHN No origin.
Piston 8409.91 $200 USA Originario

Evaluación del material intermedio (motor de arranque)

Regla T-MEC: BOTH (Tabla B, EITHER — el productor elige)

  • Sub-VCR: ($548 − $50) / $548 = 90.88% ≥ 70% ✓
  • Brinco: bobina 8511.90 no cambia de subpartida frente a 8511.40 ✗
  • Decisión: regla BOTH es EITHER → basta con que uno cumpla → PASA por VCR
Resultado del motor completo: el subensamble entero ($548) cuenta como originario. Total: $548 + $200 = $748 originario, $0 no originario. VCR = 100% ≥ 75% → PRODUCTO ORIGINARIO

Mismo BOM pero sin marcar el motor de arranque como intermedio

Los componentes se evalúan individualmente; no se aplica regla al subensamble.

ComponenteValorOrigen
Carcasa 8511.90$100MEXOriginaria
Bobina 8511.90$50CHNNo origin.
Piston 8409.91$200USAOriginario
Resultado: $300 originario + $50 no originario. VCR del motor = (350 − 50) / 350 ≈ 85.7%. Aunque pasa el VCR del 75%, faltarían más componentes para verificar el cálculo completo. En el demo del cliente, esta variante daba NO ORIGINARIO por brinco al evaluar componente a componente — la declaración como intermedio era la diferencia.

Cuando el material intermedio NO cumple su regla

Si el motor de arranque no cumple ni VCR ni brinco, el algoritmo "se cae" a desglosar sus componentes.

ComponenteValorOrigen
Motor de arranque 8511.40 $548 Intermedio Desglosado
Carcasa$100 MEXAporta
Bobina$50 CHNVMNO
Componentes no originarios extras$398 ASIAVMNO
Resultado: el subensamble como bloque no califica, pero sus componentes originarios ($100 carcasa) siguen aportando al VCR del producto padre. El padre debe verificar si su VCR total alcanza el umbral con los componentes "drilleados".

Diferencias clave entre los 3 casos del algoritmo

Caso 1 — Comprado

sourcing_type = PURCHASED. No se explota. Se trata como leaf con su origen propio (proveedor / certificado / país).

Caso 2 — Subensamble común

sourcing_type = INTERNAL + is_intermediate_material = false. Sin regla propia. Cada hijo aporta su origen individual al padre.

Caso 3 — Material intermedio

sourcing_type = INTERNAL + is_intermediate_material = true. Se evalúa contra su propia regla. Si cumple, todo el valor cuenta como originario.

Cómo lo captura el cliente

El cliente declara estos flags en su carga de datos (template CSV o formulario UI):

Importante: la decisión "esto es material intermedio" la toma el productor (cliente). El algoritmo se limita a procesar la declaración. Si la declaración es incorrecta, el resultado será incorrecto.