Saltar al contenido principal

Guía: Lectura desde GET · ← Aplicación

rule_effects — referencia completa

info

Campo en la respuesta GET

En GET /discounts y GET /discounts/{id}, este bloque viene en **rule_effects** (string JSON). Valida rule_group para bundle (no variantes legacy como rule_grouped en samples antiguos).

Define qué beneficio otorga la campaña (descuento monetario, sustitución de precio por producto, precio combo, etc.) y cómo se reparte entre el carrito y las líneas.

Pregunta que responde: «Si la campaña ganó, ¿cuánto descuenta o qué muestra, y sobre qué base del carrito?»

Aquí **rule_group** (agrupación bundle en el efecto) sí importa para integraciones — a diferencia de bundle / grouped en rule_conditions, que son internos y se ignoran.

Índice​


Campos comunes en GET​

CampoRol
key / typeIdentifican el efecto; suelen coincidir (percentage, direct_value, …)
valueMagnitud principal (% o importe). No aplica en strikethrough ni en formula
unitSolo **ratio**: unidad monetaria de referencia (p. ej. cada 10 €)
distributionCómo se reparte el efecto (ver tabla por tipo más abajo)
limitsVeces máximas que el efecto puede aplicar en la misma transacción
rule_grouptrue = agrupación / bundle (solo percentage, direct_value, combo_price). Requiere cantidades en condiciones + aplicación — ver Mecánica bundle
formulaSolo efecto **formula**: expresión fija de cálculo
strikethrough_dataSolo **strikethrough**: mapa clave producto → precio promocional. La clave puede ser **product_id** o **product_code** según use la compañía (debe coincidir con el identificador de línea en el carrito)

limits (límite del efecto, no de victoria)​

limits en rule_effects acota cuántas veces puede aplicarse el efecto en la misma transacción (mismo ticket). No es el tope de victoria de la campaña (once, presupuesto, etc.) ni un límite de unidades en rule_conditions.

ValorInterpretación
0Sin límite: el efecto puede aplicarse todas las veces que correspondan según condiciones y aplicación
> 0Como máximo esa cantidad de aplicaciones del efecto en el carrito

Qué cuenta como «una aplicación» depende de distribution y de rule_group:

ConfiguraciónQué cuenta como 1 aplicaciónQué limita limits: N
distribution: individual_items y rule_group null / falseUna unidad (línea interna de cantidad 1; ver expansión abajo)Máximo de unidades bonificadas en el carrito
rule_group: true (bundle / 2x1 / combo)Un grupo armado según quantity en rule_conditions + rule_applicationMáximo de grupos que reciben el beneficio (p. ej. cuántos 2x1)

Una unidad = una línea en el motor (aunque el carrito traiga quantity > 1)​

Para el cálculo de efectos, Loyal Guru trata cada unidad como una línea independiente. Si la integración envía una sola línea con quantity: 10, el motor la descompone internamente en 10 líneas de cantidad 1, ejecuta condiciones, rule_application, efectos y limits sobre ese modelo unitario y, al terminar, reagrupa el resultado en las mismas líneas que llegaron en el carrito (mismo número de líneas y cantidades que envió el retailer).

Implicaciones para integraciones:

  • Con distribution: individual_items, limits cuenta unidades (líneas internas de qty 1), no necesariamente filas del JSON de lines[]. limits: 10 con una línea agregada de qty 15 → como mucho 10 unidades con descuento en esa línea (las 5 restantes de esa línea, al precio pleno para ese efecto).
  • En POST /carts, effects[] puede mostrar el descuento consolidado por línea original; la lógica interna siguió el modelo unitario.
  • Condiciones de victoria y aplicación también se evalúan sobre unidades expandidas cuando el motor lo requiere; la expansión es transparente para quien solo lee el GET de campaña, pero importa al interpretar limits y al depurar tickets con líneas multi-cantidad.

Ejemplo: % por producto con tope de unidades (sin bundle)​

Objetivo: 5 % sobre determinados productos, como máximo en 10 unidades del carrito.

CampoValorPor qué
typepercentageDescuento porcentual
value55 %
distributionindividual_itemsEl % se calcula por unidad (línea interna de qty 1)
rule_groupnull o falseSin agrupación: cada aplicación = una unidad
limits10Como mucho 10 unidades reciben el 5 % en esa compra

rule_application debe acotar los productos (p. ej. product_id o product_categories en las líneas). Si el carrito trae una línea con quantity: 15 del producto elegible, el motor la trata como 15 unidades; con limits: 10 solo 10 llevan el 5 % (en la respuesta suele verse reflejado en esa misma línea agregada). Si hay varias líneas en lines[], el tope de 10 se reparte entre unidades de todas ellas según prioridad/apilamiento.

{
"type": "percentage",
"value": 5,
"distribution": "individual_items",
"rule_group": null,
"limits": 10
}

Ejemplo: 2x1 con tope de grupos (con rule_group)​

Objetivo: mecánica 2x1 pero solo dos 2x1 por ticket (dos grupos bonificados).

CampoValorPor qué
rule_grouptrueCada aplicación = un grupo (par 2+1), no una línea suelta
limits2Como mucho 2 grupos con beneficio en la transacción

Condiciones de victoria (rule_conditions) definen el tamaño del grupo (p. ej. quantity ≥ 2); rule_application cuántas unidades del grupo llevan dto. (p. ej. ≥ 1). Detalle completo: Mecánica bundle (rule_group) — ahí el mismo carrito con 8 unidades y limits: 2 solo bonifica 2 de 4 grupos posibles.

No confundir con límites de victoria (once, num_per_day, presupuesto, etc.) en la configuración general de la campaña.

Distribuciones permitidas por tipo de efecto​

Efectototalindividual_itemsindividual_items_pro_rata
percentage✓✓✓
direct_value✓✓✓
ratio✓✓✓
strikethrough—✓ (única)—
combo_price✓—✓
formula—✓ (única)—
DistribuciónComportamiento breve
totalUn solo descuento sobre el conjunto calificado / total de la transacción
individual_itemsEl efecto se evalúa por unidad (cada unidad como línea interna de qty 1; ver expansión unitaria)
individual_items_pro_rataEl beneficio se reparte proporcionalmente entre las líneas calificadas

Apilamiento (stackability) por efecto​

EfectoModo en carrito
strikethroughSiempre Highest Discount
combo_priceSiempre Highest Discount
percentage, ratio, direct_value, formulaStackable o Highest Discount (configurable)

Detalle: Apilamiento.


percentage​

Descuento porcentual sobre líneas o total calificado.

{
"key": "percentage",
"type": "percentage",
"value": 20,
"limits": 0,
"formula": null,
"rule_group": null,
"distribution": "individual_items"
}
CampoLectura
value: 2020 % de descuento
distribution: individual_itemsEl % se aplica en cada línea que cumpla aplicación
limits: 0Sin tope de unidades bonificadas; con limits: 10, como mucho 10 unidades — ver ejemplo % con tope
rule_group: nullSin agrupación (p. ej. % simple en categoría). Con true, activa grupos según quantity en condiciones y aplicación

Integración: si el descuento no aparece en las líneas esperadas del carrito, revisar **rule_application** además del % — en carrito, la aplicación suele ser obligatoria para % por línea (Detalles operativos §5).


direct_value​

Importe fijo de descuento (moneda de la campaña).

{
"key": "direct_value",
"type": "direct_value",
"value": 5,
"limits": 0,
"formula": null,
"rule_group": null,
"distribution": "individual_items"
}
CampoLectura
value: 55 € (u otra moneda) según currency de la campaña
distribution: individual_items5 € por línea calificada; con total, un único bloque de 5 € sobre el conjunto
rule_groupIgual que en percentage: true para bundles que reparten un importe fijo en grupo

Caso frecuente: €5 de dto. en cesta → direct_value, distribution: total, condición total_cart >= X.


ratio​

Beneficio proporcional al gasto en unidades monetarias: por cada unit € gastados (en base calificada), se otorga value de beneficio, repartido según distribution.

{
"key": "ratio",
"type": "ratio",
"unit": 10,
"value": 1,
"limits": 2,
"formula": null,
"distribution": "individual_items_pro_rata"
}
CampoLectura del ejemplo
unit: 10, value: 1Cada 10 € calificados → 1 de descuento (u otro beneficio según modo de campaña)
distribution: individual_items_pro_rataEse beneficio se prorratea entre las líneas que participan
limits: 2Como máximo 2 aplicaciones del ratio en la misma transacción (p. ej. hasta 20 € de base → 2 × 1 de beneficio si la regla lo permite)

En campañas de puntos, el mismo tipo ratio puede otorgar saldo (puntos o wallet) en lugar de descuento monetario — revisar currency / contexto de la campaña. En descuentos con este JSON, la lectura operativa es descuento escalado al gasto y prorrateo.


strikethrough​

Sustituye el precio de la línea en el carrito por el precio promocional definido en strikethrough_data. El descuento aplicado es la diferencia entre el precio enviado en el carrito y el precio promocional del efecto.

{
"key": "strikethrough",
"type": "strikethrough",
"limits": 0,
"formula": null,
"distribution": "individual_items",
"strikethrough_data": {
"233212": 1,
"343434": 9
}
}
CampoLectura
strikethrough_dataMapa { "clave_producto": precio_promocional }. La clave es el **product_id** o el **product_code** que use la compañía en catálogo/ticket — debe ser el mismo tipo de identificador que envía la integración en la línea
Sin valueLa magnitud del dto. sale del cálculo por línea (precio ticket − precio promo)
distributionSiempre individual_items (una evaluación por línea / producto)
limitsMisma semántica (0 = sin tope de aplicaciones del efecto)

Claves del mapa: en una misma campaña, las entradas suelen ser homogéneas (todas por ID numérico o todas por código). Si la compañía opera por SKU, espera claves tipo "12000041"; si opera por ID interno, claves tipo "233212".

Ejemplo numérico (por product_id): strikethrough_data["233212"]: 1, línea en ticket con ese producto y precio 3 → precio efectivo 1, descuento 2 (3 − 1).

Ejemplo (por product_code): strikethrough_data["CC-33CL-LATA"]: 0.99 — la línea del carrito debe traer el mismo product_code para que matchee.

Integración: si no aplica, comprobar tipo de clave (ID vs código) alineado con el carrito, que la clave exista en el mapa y el precio de línea enviado. Apilamiento: siempre Highest Discount.


combo_price​

Precio fijo del bundle para un grupo de productos que cumplen condiciones / aplicación.

{
"key": "combo_price",
"type": "combo_price",
"value": 10.9,
"limits": 0,
"formula": null,
"rule_group": true,
"distribution": "individual_items_pro_rata"
}
CampoLectura
value: 10.9Precio total del combo (10,9 €)
rule_group: trueEl motor agrupa líneas que cumplen la mecánica bundle antes de fijar el precio combo
distribution: individual_items_pro_rataEl ahorro del combo se reparte entre líneas del grupo. Alternativa: total (un solo bloque sobre el conjunto)
limits: 0Sin tope de veces que puede aplicar el combo en el carrito

Restricción: no usar individual_items en combo_price — solo total o individual_items_pro_rata. Apilamiento: siempre Highest Discount.


formula (efecto promocional externo)​

Descuento calculado por línea a partir de un atributo enviado por un sistema externo (precio promo precalculado).

{
"key": "formula",
"type": "formula",
"limits": 0,
"formula": "lines.total - lines.attributes.promoPrice",
"distribution": "individual_items"
}
CampoLectura
formulaFija en configuración: lines.total - lines.attributes.promoPrice
Sin valueEl importe sale del cálculo por línea
distributionSiempre individual_items
rule_groupNo usa agrupación (formula no admite bundle)

Flujo de integración: el integrador debe enviar promoPrice (u homólogo acordado) en atributos de línea del carrito. Si falta en una línea, esa línea no recibe dto. por esta campaña. Si el resultado ≤ 0, no aplica descuento en esa línea.


Mecánica bundle (rule_group)​

En Owner App, Bundle / grupo (rule_group: true) indica al motor que forme grupos de líneas y aplique el efecto por grupo, no línea a línea de forma independiente.

Dónde aplica​

rule_effects.rule_groupTipos de efecto compatibles
truepercentage, direct_value, combo_price
false / nullCualquier efecto sin agrupación
No disponibleratio, strikethrough, formula

Los tres bloques que definen el bundle​

BloquePregunta que respondeQué validar en integración
**rule_conditions**¿Cuántas unidades hacen falta para formar un grupo?Misma cláusula de producto/categoría + subcondición quantity (ej. gte 2 → grupos de 2)
**rule_application**¿Sobre cuántas unidades del grupo cae el efecto?Misma familia de producto/categoría + subcondición quantity (ej. gte 1 → 1 unidad con beneficio por grupo)
**rule_effects**¿Qué beneficio y cuántas veces?rule_group: true, value / type, distribution, **limits**

Los flags bundle y grouped en el JSON de condiciones/aplicación son internos (ignorar valor). Lo operativo son las **quantity** anidadas y **rule_group** en el efecto.

Ejemplo completo: 2x1 del producto 2222 (100 % en 1 de cada 2)​

Victoria — armar grupos de 2 unidades (rule_conditions):

{
"conditions": {
"and": [
{
"key": "cart_product_id",
"field": "product_code",
"bundle": 1,
"values": ["2222"],
"grouped": true,
"operator": "in",
"conditions": [
{ "field": "quantity", "value": 2, "operator": "gte" }
],
"array_field": "lines"
}
]
}
}

Aplicación — el dto. va sobre 1 unidad por grupo (rule_application):

{
"conditions": {
"and": [
{
"key": "cart_product_id",
"field": "product_code",
"bundle": 1,
"values": ["2222"],
"grouped": true,
"operator": "in",
"conditions": [
{ "field": "quantity", "value": 1, "operator": "gte" }
],
"array_field": "lines"
}
]
}
}

Efecto — 100 % en esa unidad, con agrupación activa (rule_effects):

{
"key": "percentage",
"type": "percentage",
"value": 100,
"limits": 1,
"formula": null,
"rule_group": true,
"distribution": "individual_items_pro_rata"
}

Interpretación del 2x1​

PasoLectura
Condiciones quantity: 2Cada grupo válido = 2 unidades del producto 2222 en el carrito
Aplicación quantity: 1Dentro de cada grupo, el 100 % aplica sobre 1 unidad (la “gratis” o bonificada del 2x1)
rule_group: trueEl motor agrupa antes de calcular; sin esto, el % se interpretaría línea a línea sin mecánica 2x1
distribution: individual_items_pro_rataReparto del descuento de la unidad bonificada entre líneas del grupo (habitual en 2x1)
Ticket con 8 unidades 22228 ÷ 2 = 4 grupos → hasta 4 aplicaciones del efecto (4 unidades bonificadas si no hay tope)

limits del efecto con bundles​

Con rule_group: true, cada aplicación del efecto es un grupo (no una línea suelta). Por eso limits: 2 en un 2x1 significa «como mucho dos 2x1 en el carrito», no «dos unidades en total». Ver también ejemplo 2x1 con tope de grupos.

limitsEn el ejemplo 2x1
0Sin tope: todos los grupos posibles en el carrito reciben beneficio (8 uds. → 4 grupos → 4 bonificaciones)
1Solo 1 grupo recibe el efecto en la transacción (1 producto “gratis”, aunque haya más grupos posibles)
2Máximo 2 grupos (dos 2x1); con 8 uds. en ticket solo se bonifican 2 de los 4 grupos posibles

**limits** cuenta aplicaciones del efecto por transacción (grupos bonificados con rule_group, o líneas con individual_items sin grupo), no unidades totales en el carrito.

Resumen visual​

Ticket: 8 × producto 2222
│
rule_conditions (qty ≥ 2) → 4 grupos de 2
│
rule_application (qty ≥ 1) → 1 unidad con dto. por grupo
│
rule_effects (100%, rule_group) + limits
│
limits: 0 → 4 bonificaciones (4 grupos)
limits: 2 → 2 bonificaciones (solo 2 de 4 grupos)

Variantes habituales​

MecánicaCondiciones (grupo)Aplicación (beneficio)Efecto típico
2x1 mismo productoquantity gte 2 en productoquantity gte 1 en mismo productopercentage: 100 + rule_group: true
3x2 en categoríaquantity gte 3 en categoríaquantity gte 1 en categoríapercentage: 100 + rule_group: true
Bundle A + B + C productos por €10quantity gte 1 en A + quantity gte 1 en B + quantity gte 1 en Cfiltro de líneas del bundlecombo_price + rule_group: true
€ fijo por grupoquantity gte Nquantity gte 1direct_value + rule_group: true

Errores frecuentes — bundle​

SíntomaCausa habitual
2x1 no funcionarule_group: false o falta subcondición quantity en condiciones o aplicación
Bonifica de máslimits: 0 con muchos grupos en ticket; subir limits para capar grupos bonificados
Bonifica de menoslimits bajo (ej. 1) con muchas unidades; o condiciones exigen más unidades que las del carrito
Producto distinto en aplicaciónvalues / field en aplicación no coinciden con condiciones de victoria
Confundir flags bundle/groupedNo activan la mecánica solos; hace falta **rule_group: true** y las **quantity** correctas

Configuración vs respuesta de carrito​

ContextoCampoQué contiene
Campaña en GETrule_effects (a menudo string JSON)Configuración: type, value, distribution, limits, …
Ticket / compra evaluadaeffects[]Resultado runtime por línea o bloque

Campos típicos en **effects[]** del carrito:

Campo en ticketRelación con config
effectTypeCorresponde a rule_effects.type (percentage, direct_value, …)
distribution_typeCorresponde a rule_effects.distribution
discount_valueImporte ya calculado aplicado en esa línea o bloque
rule_idID de la campaña que generó el efecto

Ejemplo (descuento % en línea):

{
"effects": [{
"rule_id": 101,
"line": 1,
"type": "discount",
"effectType": "percentage",
"distribution_type": "individual_items",
"discount_value": 1.50
}]
}

Integración: si el carrito no refleja el descuento del GET, comparar rule_effects con effects[] de la respuesta; si effects[] está vacío, revisar elegibilidad (rule_conditions, audiencia, cupón) o rule_application, no solo el tipo de efecto.


Errores frecuentes — rule_effects​

ConfusiónCómo resolverlo
limits: 0 «desactiva límites»Correcto: sin tope de aplicaciones del efecto en la transacción
Una línea con quantity: 20 y limits: 10El motor expande a 20 unidades; solo 10 reciben el efecto; la respuesta puede seguir siendo una línea con el descuento agregado — ver expansión unitaria
limits vs límites de victoriarule_effects.limits = repeticiones del efecto; once / num_* = cuántas veces puede ganar la campaña el cliente
Bundle / 2x1Trío: quantity en rule_conditions (tamaño grupo) + quantity en rule_application (uds. con dto.) + rule_group: true + limits
strikethrough «no descontó lo esperado»Clave del mapa (product_id vs product_code) debe coincidir con el identificador de la línea en el carrito; dto. = precio ticket − precio promo
combo_price con individual_itemsInválido en producto; usar total o individual_items_pro_rata
formula sin promoPrice en líneaIntegración incompleta; dto. 0 en esa línea
% o ratio sin aplicación en carritoRevisar rule_application — suele ser obligatoria para % por línea
Mismo % en config y distinto en ticketRevisar stackability (Highest Discount ganó otra campaña) y effects[]


Volver: Lectura desde GET · Checklist