Cómo implementar un nuevo tipo de descuento y promoción
IMPORTANTE: ESTA ES UNA VERSIÓN BETA
Esta página está en desarrollo activo y puede contener funcionalidades inestables o incompletas. Úsela bajo su propia responsabilidad.
Visión general
Un tipo de descuento y promoción es una implementación de una regla para Modificación de precios. Estas reglas definen la lógica que se aplicará para calcular el descuento cuando el descuento o la promoción puedan aplicarse.
Este procedimiento está dirigido a desarrolladores que deseen implementar este tipo de reglas. Los usuarios que necesiten configurar las existentes deberían leer Modificación de precios en su lugar.
Es posible definir tipos que se encarguen de una sola línea, como descuento del X por ciento en un único producto, y tipos que analicen todo el pedido o la factura para determinar si el descuento es aplicable, por ejemplo comprando los productos X e Y, Z es gratis.
Implementación
La implementación de un Tipo de descuento y promoción se realiza dentro de un módulo. Este procedimiento asume que ya existe un módulo creado.
Especificación del tipo
Este documento explica cómo crear un tipo Compre X pague Y del mismo producto. Esta regla se aplica cuando hay al menos X unidades en una línea; en este caso, por cada grupo de X unidades, solo se pagan Y.
Por ejemplo, si la regla puede aplicarse al producto A (cuyo precio es 10€), X es 4 e Y es 3. Un pedido que incluya 4 unidades de A tendría un descuento de 10€. Un pedido que incluya 9 unidades de A tendría un descuento de 20€.
Infraestructura
Lo primero que debe hacerse es ampliar la tabla que define Modificación de precios (M_Offer) en caso de que las columnas que tiene no soporten los requisitos de nuestro tipo de descuento. En este caso necesitamos las columnas X e Y.
ALTER TABLE M_Offer ADD COLUMN em_obdisc_X numeric;
ALTER TABLE M_Offer ADD COLUMN em_obdisc_Y numeric;
Note
En este caso, el DBPrefix de nuestro módulo es OBDISC.
Ahora deben crearse las columnas en el Diccionario de la Aplicación para la tabla M_Offer: vaya a la ventana Tablas y columnas, busque la tabla M_Offer y haga clic en el botón Crear columnas desde BD.
Después, sus campos correspondientes en la ventana Modificación de precios: vaya a la ventana Windows, Tabs and Fields, busque la ventana Modificación de precios, la solapa Modificación de precios y haga clic en el botón Crear campos.
Definición del tipo de descuento y promoción
Para poner a disposición el nuevo tipo, solo necesita registrarlo en la ventana Tipos de descuentos y promociones. Cree allí un nuevo registro, seleccione el módulo en el que está trabajando y añada un nombre descriptivo.
El campo Implementador PL/SQL indica cuál es la función PL que implementa este tipo. En este caso la hemos llamado OBDISC_XY_Same_Product.
Una vez creado, este tipo estará disponible desde la ventana Modificación de precios al definir nuevas reglas.
Tenga en cuenta que es una buena práctica, para mantener esta ventana disponible, mostrar los campos creados en la sección anterior por si este tipo se selecciona. Esto puede lograrse añadiéndoles una lógica de visualización que debería ser similar a @M_Offer_Type_ID@='E08EE3C23EBA49358A881EF06C139D63', donde 'E08EE3C23EBA49358A881EF06C139D63' es el UUID del registro que se acaba de crear en Tipos de descuentos y promociones.
Implementación PL/SQL
El código que implementa el tipo es:
CREATE OR REPLACE FUNCTION obdisc_xy_same_product(p_type character varying, p_rule_id character varying, p_line_id character varying, p_priceprecision numeric, p_stdprecision numeric, p_user_id character varying, p_taxincluded character varying)
RETURNS character varying AS
$BODY$ DECLARE
v_x NUMERIC;
v_y NUMERIC;
v_apply_next VARCHAR(1);
v_mod NUMERIC;
v_chunks NUMERIC;
v_tax VARCHAR(32);
v_qty NUMERIC;
v_unitPrice NUMERIC;
v_newUnitPrice NUMERIC;
v_newGrossAmt NUMERIC;
v_newNetAmt NUMERIC;
v_newNetLine NUMERIC;
v_priceactual NUMERIC;
v_basePrice NUMERIC;
v_origGrossAmt NUMERIC;
v_origLineNetAmt NUMERIC;
v_totalPromotion NUMERIC;
BEGIN
-- 1. Obtain information about how the rule is configured
SELECT em_obdisc_x, em_obdisc_y, apply_next
INTO v_x, v_y, v_apply_next
FROM m_offer
WHERE m_offer_id = p_rule_id;
-- 2. Obtain information about the line the promotion can be
-- applied to
IF (p_type ='O') then -- Get info from Order
SELECT gross_unit_price, c_tax_id, qtyordered, priceactual,
line_gross_amount, linenetamt
INTO v_unitprice, v_tax, v_qty, v_priceactual,
v_origGrossAmt, v_origLineNetAmt
FROM c_orderline
WHERE c_orderline_id = p_line_id;
else -- Get info from Invoice
SELECT gross_unit_price, c_tax_id, qtyinvoiced, priceactual,
line_gross_amount, linenetamt
INTO v_unitprice, v_tax, v_qty, v_priceactual,
v_origGrossAmt, v_origLineNetAmt
FROM c_invoiceline
WHERE c_invoiceline_id = p_line_id;
end IF;
-- 3. Decide whether the rule can be applied
IF (v_qty < v_x) then
RETURN 'Y'; -- rule not applied, apply next one if present
end IF;
-- 4. Calculate the discount
v_mod := mod (v_qty, v_x); -- Units without discount
v_chunks := floor(v_qty / v_x); -- How many times the discount is applied
IF (p_taxIncluded = 'Y') then
v_newGrossAmt := round(v_chunks * v_y * v_unitprice + v_unitprice * v_mod, p_stdprecision);
v_newUnitPrice := round(v_newGrossAmt / v_qty, p_priceprecision);
v_newNetLine := c_get_net_price_from_gross(v_tax, v_newGrossAmt, v_newGrossAmt, p_priceprecision, v_qty);
v_newNetAmt := round(v_newNetLine * v_qty, p_stdprecision);
v_basePrice := v_unitprice;
v_totalPromotion := v_origGrossAmt - v_newGrossAmt;
else
v_newNetAmt := round(v_chunks * v_y * v_priceactual + v_priceactual * v_mod, p_stdprecision);
v_newNetLine := round(v_newNetAmt / v_qty, p_priceprecision);
v_basePrice := v_priceactual;
v_totalPromotion := v_origLineNetAmt - v_newGrossAmt;
end IF;
PERFORM M_PROMOTION_ADD(p_type, p_line_id, p_rule_id, p_taxIncluded,
v_newUnitPrice, v_newGrossAmt, v_newNetLine,
v_newNetAmt, v_totalPromotion, v_totalPromotion,
v_basePrice, p_user_id);
-- 5. return whether other discounts can be applied to this same line
RETURN v_apply_next;
END ; $BODY$
LANGUAGE plpgsql VOLATILE
Explicación del código
Las siguientes secciones explican este código. Los números del título se refieren a los números en los comentarios anteriores.
Parámetros
Cualquier función que implemente un tipo de descuento y promoción debe recibir los siguientes parámetros:
p_type: Los valores posibles son O o I. O significa pedido e I significa factura. Indica si la regla se está aplicando a una línea de pedido o a una línea de factura.p_rule_id: ID de la regla (M_Offer.M_Offer_ID) que se está comprobando.p_line_id: ID de la línea (línea de pedido o línea de factura) a la que se está aplicando la promoción.p_priceprecision: En función de la divisa del documento, la precisión que se utilizará al redondear precios.p_stdprecision: En función de la divisa del documento, la precisión que se utilizará al redondear importes.p_user_id: ID del usuario que ha invocado el proceso, utilizado al crear el descuento real con fines de auditoría.p_taxincluded: Los valores posibles son Y o N. Indica si la Tarifa aplicada al documento actual incluye (Y) o no (N) impuestos.
1. Obtener la configuración de la regla
El descuento y promoción que se está comprobando normalmente tiene cierta configuración de instancia. En nuestro caso, valores para X e Y, y si otras promociones y descuentos pueden encadenarse a esta misma línea después de aplicar este.
2. Obtener la información de la línea
Debe recuperarse la información de la línea. Tenga en cuenta que la misma función se invoca para pedidos y facturas, determinado por p_type, por lo que ambos casos deben tenerse en cuenta.
3. Decidir si la regla puede aplicarse
Este código se ejecuta para todas las promociones y descuentos que son candidatos a aplicarse a cada línea (consulte la siguiente sección). Dependiendo de las reglas que defina el tipo, es posible que esta regla candidata sea rechazada.
En este caso, si la cantidad en la línea es inferior al valor de X, la regla se rechaza. Tenga en cuenta que, como la regla no se aplica, se devuelve Y; esto significa que siempre pueden aplicarse otros descuentos.
4. Calcular el descuento
En este punto sabemos que el descuento debe aplicarse a esta línea. Es el momento de implementar realmente los importes a descontar.
Aquí es importante tener en cuenta las diferencias entre tarifas que incluyen impuestos y las que no, así como el redondeo correcto.
Finalmente, cuando todo está calculado, el descuento se inserta invocando la función M_Promotion_Add. Esta creará un nuevo registro en la tabla C_OrderLine_Offer o C_InvoiceLine_Offer.
5. Devolver
Se espera que estas funciones devuelvan un valor booleano (Y o N). Si se devuelve Y, el algoritmo continuará buscando descuentos y promociones adicionales para aplicar a esta línea; mientras que, en caso de N, el algoritmo se detendrá después de aplicar este.
Cuándo se ejecuta este código
El código que comprueba Modificación de precios (M_Promotion_Calculate) se ejecuta cuando Pedidos y facturas se completan o cuando se hace clic en el botón Calcular promociones en cualquiera de estas ventanas.
Este código restablece los precios eliminando todos los posibles descuentos y promociones aplicados previamente y busca candidatos de descuentos y promociones para aplicarlos a cada línea del documento.
Un candidato a descuento es un descuento que puede aplicarse a la línea en función de los filtros generales que define este descuento. Finalmente, el PL/SQL que implementa el tipo se encarga de decidir si el descuento se aplica o no. Por ejemplo, si X es 4 y la regla puede aplicarse a A, cualquier línea con el producto A tendrá esta regla como candidata, pero solo aquellas con una cantidad igual o superior a 4 deberían aplicarse con el descuento.
Este trabajo es una obra derivada de Cómo implementar un nuevo tipo de descuento y promoción de Openbravo Wiki, utilizada bajo CC BY-SA 2.5 ES. Esta obra está licenciada bajo CC BY-SA 2.5 por Etendo.
