Open Source

PrEDA: cálculo empírico del coste temporal de Binomial

2018-02-04 - Categorías: PHP / PrEDA
Números

El coeficiente binomial es una función muy utilizada en combinatoria. Sirve para saber el número de combinaciones de elementos que podemos hacer. Se utiliza mucho en computación para estudiar la estrategia de programación dinámica, porque ejemplifica muy bien la mejora que supone utilizar dicha estrategia. Por ejemplo, la forma de escoger de entre 6 elementos 2 de ellos, es igual al coeficiente binomial (6 2).

Continuar leyendo..


PrEDA: esquemas de programación genéricos avanzados

2018-02-03 - Categorías: PHP / PrEDA
PrEDA algoritmos genericos

Otro HOWTO, code-kata, a traer vengo hoy..

XDD vengo con este post cargado de esquemas algorítmicos para programar. Estos esquemas algorítmicos son los que nos ayudan a programar las mejores soluciones. Así conseguimos llegar a las soluciones que a veces tenemos que encontrar, pero quizá no vemos en un principio cómo. Quizá el problema lo tenemos en que tarda mucho, o necesitamos demasiado espacio de almacenamiento.

Continuar leyendo..

Magento 1: cómo sacar las ventas por método de pago

2018-01-26 - Categorías: Magento / PHP
Magento ventas por mes y método de pago

Hoy traigo otro code-kata, esta vez para Magento y hecho en PHP. Se trata de un simple script que se lanza en línea de comandos. Con este script obtendremos primero todos los métodos de pago que se han usado al hacer los pedidos. Después, haremos un listado, por método de pago, y entre ciertas fechas, del monto de pedidos completados por método de pago.

Es decir, supongamos que queremos saber cómo han ido las ventas con el método de pago por tarjeta de crédito. O quizá queremos saber si la financiación es un método de pago que funciona bien. O quizá simplemente queremos tener el total de ventas entre fechas.

Pues todo esto es bastante sencillo sabiendo donde está cada cosa.

Métodos de pago usados en pedidos

A saber, los pedidos en Magento 1 guardan parte de sus datos principales en la tabla sales_flat_order. La información del método de pago utilizado en cada pedido se guarda en la tabla sales_flat_order_payment.

Entonces, sacando la columna method de la tabla sales_flat_order_payment tendremos todos los métodos de pago utilizados en los pedidos. Esto en lenguaje SQL queda así:

SELECT distinct(sfop.method)
FROM sales_flat_order_payment sfop
ORDER BY sfop.method ASC;

Ventas de los pedidos enviados

El siguiente paso será saber cómo sacar las cantidades de los pedidos completados. A saber, los pedidos completados se quedan con un status=complete y state=complete. Sí, es raro, Magento tiene internamente dos estados en cada pedido. Uno llamado status y otro llamado state. Estos estados están respectivamente en sus columnas. Así la consulta a la base de datos en SQL para sacar las ventas de un método de pago queda así:

SELECT sum(sfo.grand_total) total_sold
FROM sales_flat_order sfo
JOIN sales_flat_order_payment sfop ON sfop.parent_id = sfo.entity_id
WHERE sfo.state = 'complete' AND sfo.state = 'complete' AND sfop.method LIKE '".$methodCode."'
AND sfo.created_at > '".$startDate->format('Y-m-d H:i:s')."'
AND sfo.created_at < '".$endDate->format('Y-m-d H:i:s')."'"

Fíjate que la tabla sales_flat_order_payment se relaciona con sales_flat_order de la forma que marco en negrita.

El código completo

Ahora bien, haciendo un poco de ejercicio con un par de bucles, programando el script completo, nos queda algo tal que así:

<php

require_once __DIR__.'/app/Mage.php';

Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

// Loading arguments.
if ($argc == 3) {
    $yearFrom = $argv[1];
    $yearTo = $argv[2];
} else {
    echo 'ERROR: Incorrect number of arguments.'.PHP_EOL;
    exit;
}

$sqlConnection = Mage::getSingleton('core/resource')->getConnection('core_read');

// Loading available method codes.
$query = 'SELECT distinct(sfop.method)
    FROM sales_flat_order_payment sfop
    ORDER BY sfop.method ASC;';
$methods = $sqlConnection->fetchAll($query);
$methodCodes = array();
foreach ($methods as $method) {
    $methodCodes[] = $method['method'];
}
//var_dump($methodCodes);

// Printing table in CSV format from January to December..
echo 'PAYMENT_METHOD';
for ($year = $yearFrom; $year <= $yearTo; ++$year) {
    for ($month = 1; $month <= 12; ++$month) {
        echo ','.$year.$month;
    }
}
echo PHP_EOL;
foreach ($methodCodes as $methodCode) {
    echo $methodCode;
    for ($year = $yearFrom; $year <= $yearTo; ++$year) {
        for ($month = 1; $month <= 11; ++$month) { 
            $startDate = new DateTime($year.'-'.$month.'-1 00:00:00'); 
            //echo 'Date from: '.$startDate->format('Y-m-d H:i:s').PHP_EOL;
            $endDate = new DateTime($year.'-'.($month + 1).'-1 00:00:00');
            //echo 'Date to: '.$endDate->format('Y-m-d H:i:s').PHP_EOL;

            $query = "SELECT sum(sfo.grand_total) total_sold
            FROM sales_flat_order sfo
            JOIN sales_flat_order_payment sfop ON sfop.parent_id = sfo.entity_id
            WHERE sfo.state = 'complete' AND sfo.state = 'complete' AND sfop.method LIKE '".$methodCode."'
            AND sfo.created_at > '".$startDate->format('Y-m-d H:i:s')."'
            AND sfo.created_at < '".$endDate->format('Y-m-d H:i:s')."'";
            $amount = $sqlConnection->fetchOne($query);
            echo ','.$amount;
        }
        $startDate = new DateTime($year.'-12-1 00:00:00');
        //echo 'Date from: '.$startDate->format('Y-m-d H:i:s').PHP_EOL;
        $endDate = new DateTime($year.'-12-31 23:59:59');
        //echo 'Date to: '.$endDate->format('Y-m-d H:i:s').PHP_EOL;

        $query = "SELECT sum(sfo.grand_total) total_sold
        FROM sales_flat_order sfo
        JOIN sales_flat_order_payment sfop ON sfop.parent_id = sfo.entity_id
        WHERE sfo.state = 'complete' AND sfo.state = 'complete' AND sfop.method LIKE '".$methodCode."'
        AND sfo.created_at > '".$startDate->format('Y-m-d H:i:s')."'
        AND sfo.created_at < '".$endDate->format('Y-m-d H:i:s')."'";
        $amount = $sqlConnection->fetchOne($query);
        echo ','.$amount;
    }
    echo PHP_EOL;
}

Este script tendremos que ponerlo en el directorio raiz del proyecto Magento para que enganche al Magento. Fíjate que necesita de dos parámetros de entrada que son el año de inicio y el año de fin. Además he marcado un objeto que proporciona Magento para estas cosas, la conexión a la base de datos que se guarda en $sqlConnection.

Ejecutando

Guardamos el script anterior en un fichero, por ejemplo llamado script.php. Si queremos las ventas desde el año 2017 al 2017, lo ejecutamos así desde línea de comandos:

$ php script.php 2017 2017

Veremos la salida por pantalla. Ahora bien, si redireccionamos la salida del script a un fichero, luego podremos visualizarlo mejor. Para esto lo ejecutamos así:

$ php script.php 2017 2017 > ventas_por_metodo_de_pago.csv

Ahora abrimos el fichero CSV con nuestro programa de hojas de cálculo favorito para ver los datos. Si no tienes, es muy recomendable el LibreOffice que lo puedes descargar gratis haciendo click aquí.

Así jugando un poco con los datos resultantes, podemos tener una gráfica de evolución de los métodos de pago. Como la imagen de cabecera de arriba. Podemos ver que algo está pasando en abril y por Navidades del año 2017 con uno de los métodos de pago.

Espero que sirva.

Un saludo.


PHP: qué es un Singleton y para qué nos puede servir

2018-01-21 - Categorías: General / PHP
Coding

Ya vengo a la carga con nuevo material. Hoy con un patrón de diseño de software que puede que necesitemos. Se trata del Singleton, que simplemente es un tipo de objeto de programación. En Programación Orientada a Objetos (POO), tenemos este tipo de objetos que se usan para sólo instanciar uno y exclusivamente uno en todo el programa.

No sabemos cuántas veces ni en cuántos lugares se va a usar el objeto. Pero sí que sabemos que necesitamos que sólo exista uno como máximo. De aquí que viene su nombre de Singleton.

Porqué

La razón de ser de los Singletones es que sólo exista una instancia del objeto en todo el programa, y que sea accesible desde todo el programa. Se usa para guardar datos o funcionalidades globales, compartidas por todo el programa. Además, esta forma de carga única y acceso global mejora el rendimiento ya que la creación del objeto se hace una vez, guardándose en memoria todo el rato hasta que finaliza la ejecución. También mejora el rendimiento porque si no se instancia nunca el objeto, no se crea, con lo que no se gasta tiempo ni espacio innecesariamente.

La idea general es, limitar el uso del constructor por defecto de la clase, de forma que no se pueda llamar para construir instancias de este objeto. Y mediante otra función llamada getInstance() controlar que sólo se llame al contructor en la primera vez. En las siguientes llamadas a la función getInstance() simplemente se devuelve el objeto que ya lo tenemos creado.

El código

<?php

class MySingleton
{
    private static $instance;
    private $counter;

    private function __construct()
    {
        echo 'Contruyendo objeto..'.PHP_EOL;
    }

    public static function getInstance()
    {
        if (!self::$instance instanceof self) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    public function hazAlgo()
    {
        echo 'Escribimos algo por pantalla.'.PHP_EOL;
        ++$this->counter;
    }

    public function getCounter()
    {
        return $this->counter;
    }
}

MySingleton::getInstance()->hazAlgo();
MySingleton::getInstance()->hazAlgo();
MySingleton::getInstance()->hazAlgo();

echo 'Contador = '.mySingleton::getInstance()->getCounter().PHP_EOL;

Cargamos este código en un fichero, por ejemplo en singleton.php y al ejecutarlo mediante ‘php singleton.php’ vemos algo como lo siguiente:

Contruyendo objeto..
Escribimos algo por pantalla.
Escribimos algo por pantalla.
Escribimos algo por pantalla.
Contador = 3

Mira que sólo en el primer getInstance se llama al contructor.


Magento 1: cómo cambiar la numeración de pedidos, envíos, facturas y abonos

2018-01-02 - Categorías: Magento
Magento logo

Hoy traigo otro pequeño HOWTO para trabajar con las numeraciones internas de Magento 1.9. Los pedidos, envíos, facturas y abonos se pueden numerar. Se pueden poner prefijos por defecto, o a nivel de store, puedes seleccionar distintos prefijos y numeraciones.

En un Magento original sólo te permite hasta una numeración por store para facturas, abonos, envíos y pedidos. Esto incluso se puede mejorar haciendo varias numeraciones por store, pero ya no es una configuración normal. Para hacer 2 numeraciones de facturas en una misma store habrá que controlar el evento de creación de facturas, para así ir reenumerando ‘al vuelo’, mediante programación.

La tabla con las numeraciones

Se trata de la tabla eav_entity_store, por ejemplo:

Magento Eav Entity Store

Las numeraciones siguen todas la misma estrategia. En la columna increment_last_id tendremos el último elemento numerado. Por ejemplo, miremos el último pedido numerado es el P00127586, cuyo prefijo que lo tenemos en la columna increment_prefix es el P. Entonces nos queda que el número 00127586 es la numeración. Para calcular el siguiente le suma 1 y le vuelve a poner el prefijo.

Por ejemplo, si hacemos lo mismo con la última fila, tenemos A18X010000 es el último incremento usado. Su prefijo es el A18X, con lo que para calcular el siguiente le sumará 1 a 010000. Con lo que el siguiente será A18X010001.

Configurando por store

Inicialmente no tenemos definidos valores y se numerarán sólo con números sin prefijos de letras. Pero para definirlos tenemos que tener en cuenta todas las columnas de la imagen:

  • entity_store_id: identificador interno de fila, sólo se usa para numerar cada fila.
  • entity_type_id: identificador de tipo de entidad. Estos tipos de entidades los tenemos en la tabla eav_entity_type, por ejemplo para la entidad de typo pedido tenemos un identificador 5.
  • store_id: identificador de store, podemos verlos todos en el backend de Magento, en ‘Sistema > Gestionar tiendas’. Si pasamos el ratón por encima del enlace de vista de tienda vermos los identificadores en la URL de enlace. Por ejemplo:
    ../admin/system_store/editStore/store_id/7/key/6196861892c917efe3c053d806cb7b1e/
    Al entrar a editar esta vista de tienda (store) tenemos que su ID es 7. Este es el valor que podremos usar.
  • increment_prefix: prefijo de este contador.
  • increment_last_id: último valor usado.

Espero que sirva.

Un saludo.


PHP: cómo geolocalizar visitantes, IPs o nombres de dominio

2017-12-14 - Categorías: General / GNU/Linux / PHP
La Tierra

No quiero perder las buenas costumbres, y esto de escribir en mi blog es una de ellas. Así que aquí estoy de nuevo con otro pequeño HOWTO para geolocalizar ordenadores por IP o servidores por nombre de dominio. Es realmente sencillo, un juego de niños, pero por si lo necesitas en algún proyecto aquí que lo dejo.

A continuación tienes cómo instalar en PHP5.6 las librerías en un sistema operativo Linux. Luego para PHP7 y enlaces a información sobre bases de datos relacionadas. Para geolocalizar dispositivos en Internet basta con utilizar uno de estos servicios. Quizá lo que necesitas es dar una traducción de tu sitio según la localización del visitante, mostrar mensajes por país, o desplegar países, regiones y localidades. También puedes usar las coordenadas de este servicio, pero no es muy fiable localizar con este sistema a tan bajo nivel pero por tener tendrás con esto unos datos orientativos para tu web.

Abajo del post tienes enlaces a Bases de Datos con países del mundo, regiones y localidades actualizadas. Lo mejor de todo, la versión simple es gratis para que puedas usarlo en tu proyecto. Sólo con nombrar en tu proyecto a la empresa autora.

También hay empresas que ofrecen bajo pago este servicio..

En PHP5.6

Aquí tenemos que instalar unas de librerías y la base de datos pública de GeoIP. En un servidor Linux con Ubuntu, Debian o compatible hacemos lo siguiente:

$ sudo apt-get install php-geoip
$ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
$ gunzip GeoLiteCity.dat.gz
$ sudo mkdir /usr/share/GeoIP
$ sudo mv GeoLiteCity.dat /usr/share/GeoIP/GeoIPCity.dat

Con esto ya podemos usarlo en cualquier script o programa hecho en PHP así:

<?php
var_dump(geoip_record_by_name('jnjsite.com'));

Tenemos que ver por pantalla algo parecido a:

Array
 (
 [continent_code] => EU
 [country_code] => IE
 [country_code3] => IRL
 [country_name] => Ireland
 [region] => 07
 [city] => Dublin
 [postal_code] =>
 [latitude] => 53.333099365234
 [longitude] => -6.248899936676
 [dma_code] => 0
 [area_code] => 0
 )

Tengo que decir que la latitud y longitud son bastante aproximadas. Y dependerá bastante de tu proveedor de servicios de Internet si está bien localizado en las bases de datos de MaxMind. Pero lo que es el país, región y ciudad son bastante fiables, sobretodo el país.

En PHP7

Ahora es más fácil incluso con PHP7. Sólo tendremos que instalar la siguiente librería y se nos instalará todo de una vez:

$ sudo apt-get install php-geoip

Ya está, simplemente con esto ya podemos usar en el ordenador la geolocalización mediante PHP. Hay mucha funciones disponibles.

Terminando

Sólo me queda dejar algunos enlaces interesantes:


Symfony: cómo montar una API REST de tu plataforma completa en menos de 1 hora

2017-11-27 - Categorías: PHP / Symfony
Symfony logo

Hoy traigo un pequeño HOWTO con una joya de Symfony. Se trata de un bundle, plugin o módulo (como prefieras llamarlo) para Symfony. Es una plataforma completa en origen, pero podemos sólo usar el núcleo de dicha plataforma en nuestro proyecto. Así en menos de 1 hora tendremos montada nuestra API en nuestro proyecto. Es decir, integrando el núcleo de este bundle en nuestro proyecto, se generarán automáticamente todas las funcionalidades clásicas de una API REST de todo lo que tengamos en nuestro proyecto.

Para los no duchos en el tema, una API es un punto de entrada a nuestro proyecto. Por ejemplo, si tenemos animales en nuestro proyecto, y dejamos en la API la gestión de estos animales, podremos listarlos, editarlos, crearlos o borrarlos.. Todo remotamente desde la API, desde una aplicación móvil, desde otra web, alimentando otros sistemas informáticos con esta información, cualquier cosa que se nos ocurra se puede hacer con una API.

Es decir, por excelencia las APIs son la mejor forma de interconectar sistemas informáticos. Y no es que ahora se hayan puesto de moda, sino que en el año 2000 se pusieron de moda. Y con Symfony mediante este proyecto se simplifica mucho su puesta en marcha.

Continuar leyendo..


PrEDA: minimizando tiempo en el sistema

2017-11-22 - Categorías: PHP / PrEDA
Gantt

La gestión de los proyectos es la clave: puede marcar la diferencia entre el éxito o el desastre. La gestión de las tareas no se puede hacer de cualquier forma. Por esto que se han estudiado y se han establecido muchas estrategias. No cualquier software puede ser un buen gestor de proyectos. Por esto que existen estudios que lo integran, técnicas de programación.. y sobretodo en informática, que existen multitud de estrategias, ya que dentro de los ordenadores esto se aplica constantemente.

Los pasos clásicos a seguir son los siguientes:

  • Se establecen las tareas, fijando especificaciones.
  • Se estudian bien los tiempos que va a llevar cada tarea.
  • Se establece la estrategia para proceder.
  • Se resuelve el órden, con lo cual, aquí se obtienen las fechas de finalización de cada tarea y el tiempo total.
  • Se ejecuta el proyecto.

Como es obvio, en el primer paso se cierran especificaciones y cualquier modificación posterior invalida el algoritmo, y hay que recalcular todo.

A modo de code-kata traigo hoy una estrategia voraz para organizar un proyecto con el objetivo de minimizar el tiempo de espera de las tareas en el sistema. Suponiendo que todas las tareas son igual de importantes, se trata de hacer que esperen en total lo mínimo posible. Se trata de una estregia voraz porque simplemente se elige la siguientes tareas que menos tiempo se tarde en terminar, sin rectificar ni volver atrás. Así se terminarán primero las que menos se tarde, y más rápido se irán entregando las tareas. Otra cosa es el beneficio o la importancia que pueda tener cada tarea, pero para esto hay otro algoritmo 😉

Continuar leyendo..

Symfony: cómo montar un programador de tareas en menos de 1 hora

2017-11-21 - Categorías: PHP / Symfony
Symfony logo

Cuando has valorado bien un proyecto, y es tal el nivel de personalización que se quiere alcanzar, no queda más remedio que hacer un desarrollo artesanal, o a la larga te arrepentirás. Ya que partir de un CMS prefabricado es, a veces, más que una ayuda un lastre. Cuando quieres la máxima flexibilidad, velocidad en las modificaciones.. y por supuesto, la máxima calidad.. tienes que ir al desarrollo sobre frameworks. Ya hablé sobre esto en otro post anterior..

Hoy vengo a empezar con una serie de plugins o bundles para Symfony, hoy con uno para programar tareas. Ya sea para enviar emails transaccionales, para programar tareas de marketing, crawleos de sitios web, generar sitemaps, o lo que sea que quieras automatizar.. Aquí verás como en un rato tienes montado un estupendo programador de tareas.

Con este programador de tareas ya tienes el panel de control hecho. Es decir, te evitas la construcción del panel, y podrás ir al siguiente paso en menos de una hora. Que será directamente el ir a crear las tareas tal y como las necesites para tu proyecto 🙂

Continuar leyendo..

Magento: guardando variables globales, de configuración o del core

2017-11-13 - Categorías: Magento
Magento logo

Puede ser que necesitemos en Magento alguna forma de almacenar datos globales, es decir, que no son relacionados con ningún otro elemento individual.

Todo o casi todo en Magento tiene atributos: los productos, clientes, pedidos, direcciones, facturas, abonos, etc.. Pero para almacenar estos atributos globales tenemos dos opciones, o los guardamos como variables de configuración o como variables del core de Magento.

La diferencia es que las variables de configuración se cachean y las del core no. Muchas de las variables de configuración se pueden gestionar desde el panel de control en Sistema > Configuración. Si modificamos mediante código las variables de configuración no se refrescarán los datos, sin embargo si modificamos las variables mediante el panel de control casi todas se refrescan en el momento. Sin embargo con las variables del core esto no pasa.. conforme se guardan se tienen actualizadas al consultarlas de nuevo. Usar variables del core provoca más consultas a la base de datos, sin embargo, las variables de configuración se actualizan sólo cuando se refresca la caché de variables de configuración.

Continuar leyendo..

© 2021 JnjSite.com - MIT license

Sitio hecho con WordPress, diseño y programación del tema por Jnj.