domingo, 21 de agosto de 2016

Actualización de la tarifa de transporte en Virtuemart

Llegó a mis manos una instalación de una tienda virtual en un entorno no usual (para mí). Me explico, la tienda estaba montada sobre Joomla con un extensión llamada VirtueMart. Hasta ahí todo bien (o mal, según se mire).

Esta tienda en particular, para el cálculo de los gastos de envío, tiene unas 600 líneas diferentes, diferenciando por pesos y zonas geográficas. Hasta ahí algo normal. En su día alguien picaría a mano todas las líneas, pero ahora me piden que actualice la tarifa. Algo tan fácil como aplicarle un % de subida a la tarifa podría hacerse con una instrucción SQL, algo así como: (ajustando el nombre del campo y la tabla)

UPDATE precio = precio * 1.05 FROM TARIFAS

Pues no, resulta que en este software, los datos de las tarifas no están guardados como Dios Boyce-Codd manda y me encuentro cosas del tipo:

SELECT shipment_params FROM xxxx_virtuemart_shipmentmethods;


Resumiendo, los parámetros (campos!!!!) están guardados como una cadena de texto formateada, de manera que ya no es tan sencillo hacer un "UPDATE".

Solución: habrá que usar un poquito de programación.



En primer lugar, creamos una función que nos da la funcionalidad de "SPLIT", es decir, dada una cadena de caracteres y un separador, devuelve la sección número "i".

Por ejemplo, SPLIT('primero;segundo;tercero', ';', 2) tendrá como resultado: 'segundo'

DROP FUNCTION IF EXISTS SPLIT_STRING;

DELIMITER $

CREATE FUNCTION 
   SPLIT_STRING ( s VARCHAR(1024) , del CHAR(1) , i INT)
   RETURNS VARCHAR(1024)
   DETERMINISTIC -- always returns same results for same input parameters
    BEGIN
        DECLARE n INT ;
        -- get max number of items
        SET n = LENGTH(s) - LENGTH(REPLACE(s, del, '')) + 1;

        IF i > n THEN
            RETURN NULL ;
        ELSE
            RETURN SUBSTRING_INDEX(SUBSTRING_INDEX(s, del, i) , del , -1 ) ;      
        END IF;

    END
$
DELIMITER ;



DROP Function IF EXISTS my_precios;
DELIMITER $$
CREATE FUNCTION my_precios(entrada TEXT)
  RETURNS TEXT
  LANGUAGE SQL
BEGIN
  DECLARE i INT ;
  DECLARE trozo TEXT ;
  DECLARE encontrado BOOLEAN ;
  DECLARE coste_str TEXT;
  DECLARE coste DOUBLE;
  DECLARE nuevo_coste DOUBLE;
  DECLARE nuevo_coste_str TEXT;
  DECLARE nuevo_trozo TEXT;

  SET i = 1;
  SET encontrado = false;
  REPEAT
SET trozo = SPLIT_STRING(entrada,'|',i);
IF not trozo IS NULL THEN
if trozo like '%cost%' THEN
SET coste_str = SPLIT_STRING(trozo,'"',2);
   IF not coste_str IS NULL THEN
SET coste = CAST(coste_str AS DECIMAL(10,2));
SET encontrado = true;
END IF ;
END IF;
SET i = i + 1;
END IF;
  UNTIL (trozo IS NULL) OR encontrado END REPEAT;
  if encontrado then
    set nuevo_coste = coste * 1.05;
set nuevo_coste_str = CAST(ROUND(nuevo_coste,2) as CHAR(5));
set nuevo_trozo = CONCAT('cost="', nuevo_coste_str, '"');  
return REPLACE(entrada, trozo, nuevo_trozo);
  else
return entrada;
  end if ;

END;
$$
DELIMITER ;

Con estas funciones creadas, ya podemos hacer un simple UPDATE de lo que queremos:

UPDATE `xxxx_virtuemart_shipmentmethods`
set shipment_params= my_precios(shipment_params)

Aclaración 1: Lo de poner el porcentaje como parámetro sería una mejora
Aclaración 2: Estoy seguro que debe haber alguna expresión regular que hace la sustitución sin tanta complicación, pero no tenía tiempo de ponerme a investigar por ese lado.

0 comentarios:

Publicar un comentario