Descuentos de precios de proveedores




Los descuentos de precios o los descuentos por volumen representan situaciones en las que el precio unitario marginal de los bienes varía de acuerdo con la cantidad de compra en cuestión. Generalmente, los precios unitarios disminuyen a medida que las cantidades de compra aumentan, para darle al cliente el incentivo de comprar más. Cuando los proveedores ofrecen descuentos, existe un incentivo económico que justifica el ajuste consecuente de las cantidades de compra para aprovechar esos descuentos. Envision ofrece un amplio respaldo para los descuentos de precios de proveedores. En esta sección, detallamos cómo modelar los descuentos de precios desde la perspectiva de optimización de la compra.


Representación de tabla de los descuentos de precios

El modo más frecuente de representar descuentos de precios para una lista de productos es tener una tabla de tres columnas:

  • Id el identificador del producto
  • MinQ la cantidad mínima que debe alcanzarse para ser elegible para el precio unitario
  • P el precio unitario de compra del producto

Para que la tabla resulte siempre legible, cuando observamos un determinado producto, las líneas generalmente se ordenan en cantidades en orden creciente. Este orden ayuda a darle sentido a la magnitud de los descuentos.

Esta representación tiende a una situación de precios unitarios marginales negativos, en la que comprar una unidad adicional puede tener como resultado un precio total inferior.

Consideremos que el producto A se vende a 1€ por unidad. Cada 50 unidades, al producto A se le aplica un descuento por el que el precio unitario desciende a 0,90€. Comprar 46 unidades cuesta 46€, mientras que comprar 50 unidades cuesta solo 45€. Por lo tanto, no existe un incentivo económico para comprar entre 46 y 49 unidades, ya que resulta más económico comprar 50. El precio unitario marginal de la unidad número 50 es de -4€.

Esos precios marginales negativos son consecuencia del modelo de datos subyacente adoptado para los descuentos. Existen modelos de descuentos más elaborados que son capaces de eliminar esos precios marginales negativos; sin embargo, esos modelos exceden el alcance de este artículo.

A continuación, supondremos que los datos de descuentos pueden ponerse a disposición con una tabla, como se muestra más arriba.

Función pricebrk()

El objetivo de la función pricebrk() en Envision es transformar datos de descuentos tabulares en una distribución que represente el costo de compra marginal de las unidades. La sintaxis es la siguiente:
// 'Prcs' es la tabla de descuentos
expect Prcs[Id, *] 
B = pricebrk(D, P, Prcs.MinQ, Prcs.P, Stk, StkP)
La función devuelve la distribución del precio de compra unitario marginal, es decir, el precio por pagar para comprar la unidad número k. Esta función es un tanto compleja. Detallamos y justificamos su complejidad a continuación.

Los argumentos son los siguientes:
  • D (para demanda) es una distribución utilizada para establecer un soporte —en sentido matemático— para la distribución que se devolverá. Los valores de esta distribución no se utilizan, sino que la distribución devuelta se ajusta para que sea al menos tan precisa como D.
  • P es un número, interpretado como el precio unitario predeterminado del producto. Este valor se utiliza si no existe un descuento para una cantidad mínima de 1, ya sea porque el descuento comienza con una valor mayor que uno o porque no existe un descuento para el producto.
  • Prcs.MinQ es la menor cantidad posible para la que se aplica una línea de descuento. Debe ser un entero igual o mayor que 1. No se admiten duplicados.
  • Prcs.P es el precio unitario para esta línea de descuento. Se aplica a todas las unidades compradas, no solo a las que exceden la Prcs.MinQ. Debe ser una función decreciente de Prcs.MinQ.
  • Stk es el stock disponible del producto. Los valores diferentes de cero significan que es necesario comprar menos unidades para alcanzar un nivel de stock determinado, lo que significa que es más difícil conseguir descuentos. Debe ser un entero no negativo. Este argumento es opcional. Cuando el argumento se omite, StkP también debería omitirse. Cuando este argumento se omite, el valor predeterminado es cero.
  • StkP es el precio unitario para las unidades que ya se encuentran en stock. Este argumento es opcional. Cuando se omite, el valor predeterminado es cero.

El argumento P no es más que un azúcar sintáctico pensado para gestionar las situaciones en las que la tabla de descuentos solo cubre los productos que realmente se benefician de un descuento. A través de este argumento, evitamos la necesidad de ampliar la tabla Prcs para que tenga al menos una línea por producto.

Resolución de distribuciones

Una distribución es necesaria como primer argumento de pricebrk(), porque las distribuciones en Envision no son precisas arbitrariamente. De hecho, existen límites prácticos para la resolución de una distribución dentro de Envision. No obstante, los descuentos obtenidos de un determinado proveedor pueden ir desde una compra de 1 unidad hasta (teóricamente) una compra de 10 millones de unidades. La distribución Demand es utilizada por la función pricebreak() para ajustar la resolución de la distribución devuelta al rango de interés.

De hecho, un inconveniente que Envision previene es una lógica de optimización del inventario que acaba sugiriendo comprar 999 unidades cuando el descuento objetivo se obtiene con 1000 unidades. Una situación de este tipo podría suceder si la distribución generada por Envision no diferencia internamente los valores de 999 unidades y 1000 unidades. Al pasar una distribución a la función pricebrk(), Envision se asegura de que este escenario específico se evite adaptando la resolución de la distribución devuelta.

Espacio de pedido vs espacio de stock

La tabla de descuentos se organiza desde una perspectiva de "pedido", asociada al precio de compra unitario para cada una de las cantidades compradas. Sin embargo, la perspectiva de optimización del inventario se organiza desde un punto de vista de stock: cuando consideramos agregar 1 unidad de stock, tenemos en cuenta el stock que ya está disponible, es decir, el espacio de stock. La función pricebrk() traduce la representación del descuento del espacio de pedido original en espacio de stock.

Esta traducción es el motivo por el que pricebrk() requiere dos argumentos asociados con el stock: el nivel de stock y el precio unitario del stock. Esos dos argumentos se utilizan para desplazar la distribución de precio marginal hacia la derecha por unidades de stock. El desplazamiento puede realizarse con el operador de desplazamiento normal >> en distribuciones, pero, una vez más, esto podría desencadenar situaciones en las que aproximaciones menores entran en conflicto con los umbrales de descuentos. La función pricebrk() internaliza este desplazamiento para eliminar esas aproximaciones.

Costo marginal de unidades

La distribución devuelta por pricebrk() representa el costo unitario marginal de compra. El segmento [1;Stk] se asocia al stock actual y al StkP. Luego, si B es la distribución devuelta por pricebrk(), la integral int(B, Stk + 1, Stk + N) es el costo total de compra de N unidades además de las unidades que ya están en stock.

Como se señaló anteriormente, las tablas de descuentos se asocian a menudo con costos unitarios marginales negativos, es decir, situaciones en las que la compra de una o más unidades viene con un costo negativo. Las distribuciones devueltas por pricebrk() reflejan esas situaciones a través de valores locales negativos. Esos valores negativos son consistentes y la consecuencia directa del modelo de datos de descuentos.

Combinación de descuentos y recompensas por existencias

La función de recompensa por existencias calcula la distribución de retornos económicos marginales por cada unidad adicional de inventario que se almacena en stock. En una sección anterior, vimos el modo en que esta función puede asociarse con las variables económicas que representan el margen bruto, la penalización por desabastecimientos y los costos de almacenamiento. En nuestra explicación anterior, esas variables económicas eran números simples. Sin embargo, cuando se trata de descuentos, esas variables económicas también varían, junto con la cantidad que se pide. Esas variaciones son fáciles de modelar a través de distribuciones.
B = pricebrk(D, BuyP, Prcs.MinQ, Prcs.P, Stk, StkP)

// 'M', 'S' y 'C' son distribuciones 
M = SellPrice - B
S = -0.5 * (SellPrice - B)
C = -0.3 * B * mean(Leadtime) / 365

AM = 0.3
AC = 1 - 0.2 * mean(Leadtime) / 365

// multiplicación puntual para 'RM', 'RS' y 'RC'
RM = stockrwd.m(D, AM) * M
RS = stockrwd.s(D) * S
RC = stockrwd.c(D, AC) * C
R = RM + RS + RC 
La principal diferencia entre este bloque de código y el bloque original, cuando presentamos la función de recompensa por existencias, es BuyP. La columna BuyP se vuelve una distribución de descuentos B en la línea 1 a través de la función pricebrk(). Luego, el resto del script se reduce a la aplicación directa del álgebra de distribución que hace todo el trabajo complicado por nosotros.

Entre las líneas 4 y 6, las variables económicas se convierten en distribuciones. De hecho, cuando se agrega una constante a una distribución, el resultado de la adición es una distribución. Lo mismo vale para la resta. En el script anterior, M es la recompensa marginal por unidad (también conocida como el margen marginal), y, debido a que los precios generalmente ofrecen un precio unitario menor a medida que la cantidad aumenta, se espera que la distribución M sea creciente.

Entre las líneas 12 y 14, los componentes de las funciones de recompensa por existencias se asocian con distribuciones económicas (en lugar de números), pero la sintaxis sigue siendo idéntica. Al analizarlo, se advierte que lo que sucede son multiplicaciones puntuales entre distribuciones. Por último, en la línea 15, se compone la recompensa por existencias final, como hicimos antes.