🧮 D365 SCM ya calcula descuentos multilínea por API
🧮 D365 SCM ya calcula descuentos multilínea por API
Microsoft ha ampliado el alcance documentado de la pricing calculation API de Unified Pricing Management: desde el 2 de octubre de 2026, los descuentos multilínea o de nivel carrito aparecen expresamente como soportados. Hasta el día anterior figuraban en la columna de capacidades no admitidas.
El cambio importa para portales B2B, configuradores, herramientas de oferta e integraciones de partners. Una aplicación externa puede enviar varias líneas como una sola transacción, hacer que Supply Chain Management evalúe el contexto común y recuperar precios y descuentos sin crear un pedido de venta.
No convierte esta API en un motor de checkout de Commerce. Microsoft mantiene fuera de alcance la basket pricing con concurrencia de promociones, los escaparates de comercio electrónico y las llamadas de alta frecuencia o volumen.
Diagrama original. Las líneas viajan juntas dentro de priceLookupContext; SCM devuelve el desglose por producto sin persistir un pedido.
Qué ha cambiado exactamente
La tabla de alcance oficial ahora diferencia estas capacidades:
| Soportado | Sigue sin estar soportado |
|---|---|
| Cálculo de precio por producto | Basket pricing y concurrencia de promociones de Commerce |
| Descuentos simples | Llamadas de alta frecuencia o volumen |
| Descuentos multilínea o de nivel carrito | Comercio electrónico o escenarios de escaparate |
| Reglas y atributos de Unified Pricing Management | Sustituir las API de Commerce Scale Unit |
| Precios por cantidad y rangos de variantes | — |
La distinción entre «descuento de nivel carrito» y «basket pricing» es importante. La primera expresión describe reglas que necesitan el conjunto de líneas de una transacción; la segunda pertenece a escenarios de Commerce con concurrencia, rendimiento y semántica de cesta específicos. La API de SCM puede evaluar las líneas juntas, pero no adquiere por ello el contrato operativo de un POS o una tienda web.
Microsoft no marca la API como preview. Los requisitos publicados son:
- Dynamics 365 Supply Chain Management 10.0.47 o posterior;
- Unified Pricing Management habilitado;
- una aplicación registrada en Microsoft Entra ID;
- la misma aplicación registrada en SCM y asociada a un usuario con permisos adecuados.
La documentación no anuncia un SKU ni un medidor específico para la nueva capacidad. Se mantienen los requisitos de licencia y seguridad del entorno de Supply Chain Management y del usuario de servicio utilizado por la integración.
Arquitectura y contrato
La aplicación externa no crea SalesTable ni SalesLine. Invoca un servicio JSON síncrono:
POST https://<entorno>/api/services/GUPPricingServiceGroup/GUPPricingService/getActivePrices
Authorization: Bearer <token>
Content-Type: application/json
El flujo es:
- La aplicación obtiene un token OAuth 2.0 de Microsoft Entra ID con el ámbito
https://<entorno>/.default. - SCM resuelve el
Client IDcontra System administration > Setup > Microsoft Entra ID applications y ejecuta con el usuario asociado. GUPPricingServiceconvierteHeaderContextyLineContextsen un contexto transaccional para Unified Pricing Management.- El motor evalúa precios, ajustes y descuentos aplicables a la fecha indicada.
- La respuesta contiene una
Transactiony un arrayItemResultscon el precio y el desglose de cada producto.
El servicio calcula; no documenta persistencia de un pedido ni reserva de inventario. Si la integración necesita que el precio quede fijado en un documento, debe crear o actualizar ese documento mediante un flujo separado y decidir cómo controla la vigencia entre consulta y confirmación.
Dos modos de petición
El contrato ofrece dos rutas mutuamente excluyentes:
| Entrada | Uso |
|---|---|
productIds | Consulta sencilla de productos, con cantidad predeterminada 1 |
priceLookupContext + LineContexts | Varias líneas, cantidades, unidades, almacenes, modos de entrega y atributos |
No envíes productIds y LineContexts en la misma petición. Para descuentos multilínea necesitas LineContexts, porque cada línea forma parte del contexto transaccional.
Los parámetros que gobiernan el cálculo son:
dataAreaId: empresa, obligatorio si no se proporcionaChannelId;activeDate: fecha y hora efectiva; si se omite utiliza la fecha y hora del sistema;calculateSimpleDiscountOnly:truelimita el cálculo a descuentos simples;falsetrata la entrada como una transacción para el cálculo completo;includeVariantPriceRange: devuelve mínimo y máximo de variantes cuando valetrue.
Petición multilínea completa
El siguiente ejemplo envía dos productos con cantidades distintas y solicita el cálculo completo:
{
"request": {
"dataAreaId": "usrt",
"activeDate": "2026-10-03T08:00:00+02:00",
"priceLookupContext": {
"HeaderContext": {
"CustomerAccount": "004009",
"InventorySiteId": "CENTRAL",
"InventoryLocationId": "DC-CENTRAL",
"SalesOrderProperties": [
{
"Name": "order type",
"Value": "3"
}
]
},
"LineContexts": [
{
"ProductRecordId": 22565421974,
"UnitOfMeasureSymbol": "ea",
"Quantity": 3,
"SalesLineProperties": [
{
"Name": "material",
"Value": "brass"
}
]
},
{
"ProductRecordId": 22565421975,
"UnitOfMeasureSymbol": "ea",
"Quantity": 2
}
]
},
"calculateSimpleDiscountOnly": false,
"includeVariantPriceRange": false
}
}
Los nombres son sensibles a mayúsculas y minúsculas. ProductRecordId es el identificador de registro del producto, no el ItemId. Para una línea, Quantity vale 1 si se omite. Sitio y almacén heredan primero del canal y, si no hay canal, del cliente; utiliza "" cuando necesites anular el valor heredado y dejarlo vacío.
Contexto de cabecera
HeaderContext permite enviar:
CustomerAccount;ChannelIden lugar dedataAreaIdcuando el cálculo se basa en un canal;- sitio y almacén comunes;
- afiliaciones y niveles de fidelización;
SalesOrderPropertiespara atributos de cabecera.
Las afiliaciones ya vinculadas al cliente se aplican automáticamente. Solo hay que enviarlas para añadir un contexto distinto o adicional.
Contexto de línea
Cada elemento de LineContexts puede aportar:
- producto, unidad y cantidad;
- sitio y almacén específicos;
- modo de entrega;
SalesLinePropertiescon atributos utilizados por las reglas de precio.
SalesOrderProperties y SalesLineProperties no admiten dos valores para el mismo atributo dentro de una petición. Si necesitas comparar alternativas, realiza peticiones distintas.
Interpretar la respuesta
ItemResults devuelve una entrada por producto calculado. Entre los campos documentados están:
| Campo | Significado |
|---|---|
BasePrice | Precio base del producto |
TradeAgreementPrice | Precio procedente de acuerdos comerciales |
AdjustedPrice | Precio después de ajustes |
CustomerContextualPrice | Precio final contextual para el cliente |
DiscountAmount | Descuento total aplicado |
CurrencyCode, UnitOfMeasure, Quantity | Contexto del resultado |
AttainablePriceLines | Trazabilidad de métodos y orígenes de precio |
DiscountLines | Ofertas, porcentajes e importes efectivos |
Para una integración multilínea no basta con leer CustomerContextualPrice. Conserva también DiscountLines, OfferId, SaleLineNumber y los importes efectivos para diagnosticar por qué una promoción se aplicó o no. No asumas que el orden del array sustituye a una clave estable: correlaciona por producto y los identificadores de línea que exponga el contrato.
Implementación paso a paso
1. Preparar Unified Pricing Management
Habilita Unified Pricing Management en un sandbox y configura reglas, grupos, prioridades, concurrencia y atributos. Valida primero el resultado dentro de SCM. La API consume el motor configurado; no compensa reglas incompletas ni una prioridad incorrecta.
2. Registrar la identidad
- Crea o reutiliza una aplicación en Microsoft Entra ID.
- Genera el secreto indicado por la guía oficial y protégelo en un gestor de secretos.
- Solicita el token para
https://<entorno>/.default. - En SCM, registra el
Client IDy asígnalo a un usuario dedicado. - Concede al usuario únicamente los privilegios necesarios para el servicio y los datos de pricing.
No utilices una cuenta humana ni un administrador global como usuario de integración. Rota el secreto antes de su vencimiento y evita escribir token, secreto, cliente o condiciones comerciales completas en logs.
3. Construir la petición como una transacción
Agrupa en la misma llamada todas las líneas que deban participar en la regla multilínea. Fija calculateSimpleDiscountOnly a false, envía una fecha efectiva explícita y conserva juntos empresa, cliente, canal, divisas, cantidades, unidades y atributos que condicionan el resultado.
Si divides las líneas en llamadas independientes, el motor no dispone del conjunto que necesita una regla transaccional. Si, por el contrario, mezclas líneas que pertenecen a cestas diferentes, puedes aplicar un descuento que no corresponde.
4. Tratar el resultado y la vigencia
Define qué valor utilizará el sistema consumidor y qué trazabilidad almacenará. Guarda como mínimo la fecha efectiva, empresa, cliente o canal, productos, cantidades, moneda, precio final y ofertas aplicadas. Antes de confirmar un documento mucho después de la consulta, decide si recalculas o si existe un compromiso contractual que fija el precio anterior.
5. Diseñar errores y reintentos
Usa un identificador de correlación propio y reintentos limitados para fallos transitorios. No reintentes indefinidamente errores funcionales de producto, unidad, regla o permisos. La operación es de cálculo, pero una tormenta de reintentos puede superar el perfil de frecuencia bajo o moderado que Microsoft admite.
Extensibilidad
Microsoft documenta extensiones de GUPPricingServiceClass para añadir parámetros o resultados:
initHeaderPricingObjectHashpara contexto de cabecera;initLinePricingObjectHashpara contexto de línea;setProductPricepara ampliar la salida.
Una extensión de clase debe usar [ExtensionOf(classStr(GUPPricingServiceClass))] y llamar a next. Los atributos personalizados viajan en SalesOrderProperties o SalesLineProperties; valida su nombre, tipo y valor antes de aplicarlos. No cambies el contrato estándar ni reutilices un atributo para dos semánticas distintas entre canales.
Límites que siguen vigentes
- Requiere SCM 10.0.47 o posterior y Unified Pricing Management.
- Está orientada a integraciones sistema a sistema de frecuencia baja o moderada.
- No sustituye a Commerce Scale Unit para PDP, POS, e-commerce, picos de concurrencia o navegación de catálogo.
- La documentación sigue excluyendo basket pricing y concurrencia de promociones de Commerce.
- No crea un pedido, reserva inventario ni promete mantener el resultado hasta la confirmación.
activeDatey los valores predeterminados pueden cambiar el resultado; no dependas implícitamente del reloj del servidor.- El contrato usa IDs de producto y varios nombres sensibles a mayúsculas.
- El rendimiento debe probarse con el número real de líneas y reglas, sin extrapolar desde una petición unitaria.
Matriz de pruebas
| Caso | Validación |
|---|---|
Una línea, calculateSimpleDiscountOnly: true | Mantiene el comportamiento simple existente |
Varias líneas, false | Aplica la regla multilínea esperada y devuelve desglose por línea |
| Umbral justo por debajo y por encima | El descuento aparece solo cuando corresponde |
| Dos unidades de medida | Cantidad y conversión no alteran indebidamente el umbral |
| Cliente y canal | Se aplican contexto y afiliaciones correctos |
| Sitio/almacén omitido, vacío y explícito | Se valida la herencia documentada |
| Fecha actual y fecha futura | Vigencias de reglas y acuerdos son correctas |
| Atributos de cabecera y línea | Prioridades y condiciones coinciden con SCM |
| Dos promociones concurrentes | Se comprueba el límite frente a Commerce, no se presupone paridad |
| Carga baja, media y ráfaga | Latencia, errores y reintentos permanecen dentro del diseño |
Compara el resultado con una transacción equivalente dentro de SCM. Verifica no solo el precio final, sino también DiscountLines, origen, moneda, unidad, cantidad y regla efectiva.
Recomendación práctica
La ampliación elimina una barrera importante para cotizadores y portales B2B internos: ya no necesitan calcular cada línea aislada cuando una regla depende del conjunto. Diseña la llamada como una transacción inmutable, utiliza calculateSimpleDiscountOnly: false y conserva el desglose devuelto.
Mantén, sin embargo, una frontera clara. Si el caso es un escaparate público, un POS o una cesta con concurrencia compleja de promociones y gran volumen, la API correcta sigue siendo Commerce Scale Unit. El nuevo soporte aporta cálculo multilínea en SCM; no convierte SCM en el plano de pricing de una tienda de alta escala.