Programacion Interactiva

Descubre una Nueva y Poderosa Herramienta.

FrameWork de Nueva Generacion

Acceso a tu Informacion desde cualquier Dispositivo con Navegador.

Enfoque en el Backend

Frontend de forma facil con Odoo y XML.

Creacion de Verticales

Creacion de nuevas Verticales Conquistando nuevos Mercados.

Tu marca aqui mismo

Llega a miles de personas.

Publicidad

miƩrcoles, 3 de junio de 2020

Consulta SQL en Odoo implementando nuestra Zona horaria

Consulta SQL en Odoo corrigiendo el error de la zona horaria en el resultado de la consulta de un periodo



     La siguiente Consulta SQL resuelve el error de la Zona Horario Odoo, como sabran la base de datos se encuentra en UTC o zona horaria central por lo cual visualmente dentro del sistema se realiza la conversión a la zona horaria del usuario y se muestra correctamente, pero en base de datos podemos tener una diferencia en campos fecha/hora, por lo cual al realizar una consulta esta puede abarcar un periodo que no es correcto, para ello lo unico que requerimos es dentro de la conulta convertir la columna de fecha/hora a nuestra zona horaria, para este ejemplo utilizare la zona horaria de Mexico UTC-6.

Las librerias que utilizaremos son:


from datetime import timedelta, datetime



La clave esta en convertir la columna fecha/hora a UTC-6

   

        start_period = self.date_start + " 00:00:01"
        start_period_strp = datetime.strptime(start_period, '%Y-%m-%d %H:%M:%S')
        start_period_tz = fields.Datetime.context_timestamp(self, 
        timestamp=start_period_strp)
        end_period = self.date_stop + " 23:59:59"
        end_period_strp = datetime.strptime(end_period, '%Y-%m-%d %H:%M:%S')
        end_period_tz = fields.Datetime.context_timestamp(self, 
        timestamp=end_period_strp)
        get_list_contacts_partner = self.get_parners_list(self.supplier_id)

        product_list = []


        cr.execute("""

            insert into supplier_puchase_detail_record(  supplier_id,

                                                        product_id,

                                                        uom_id,

                                                        qty_total,

                                                        qty_available

                                                        )

            select  %s,

                    stock_move.product_id,

                    stock_move.product_uom,

                    sum(stock_move.product_uom_qty),

                    0.0

            from stock_move

                 join stock_picking

                   on stock_move.picking_id = stock_picking.id

                 join purchase_order_line

                   on purchase_order_line.id = stock_move.purchase_line_id

            where stock_picking.partner_id in %s

            and (stock_picking.date_done at time zone 'UTC-6') between %s and %s

            group by stock_move.product_id, stock_move.product_uom

           

            """, (self.supplier_id.id,
                  tuple(get_list_contacts_partner), 
                  start_period_tz, end_period_tz))

Nginx SSL - ERR_SSL_PROTOCOL_ERROR - No se puede conectar por SSL (Solución)

Solución al error con Nginx ERR_SSL_PROTOCOL_ERROR




139857146823744:error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error:../ssl/record/rec_layer_s3.c:1528:SSL alert number 80


El error esta en la configuración de nuestro sitio nginx, para ser exactos en el apartado de configuración ssl debemos modificar y de ser necesario cambiar o reemplazar los sig. parÔmetros:


    ssl_prefer_server_ciphers on;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;


TEST de CONEXION SSL



openssl s_client -connect jlbelleza.es:443 -servername midominio.mx


El parƔmetro midominio.mx es el sitio al cual se estƔn conectando e implementando el certificado SSL.

Implementando STP con Python

Como utilizar SFTP desde Python


El fragmento para poder copiar un archivo a un servidor sftp es el siguiente:
import paramiko
import os

paramiko.util.log_to_file('logfile.log')

host = "101.102.103.104"
port = 22
transport = paramiko.Transport((host, port))
password = "pass"
username = "user"
transport.connect(username = username, password = password)


sftp = paramiko.SFTPClient.from_transport(transport)

filepath = '~/remote/file'
localpath = '~/local/file'
sftp.get(filepath, localpath)

sftp.close()
transport.close()

Espero que les sea de utilizad.

Solucion al error con la libreria sassc: error: no such option: --stdin ()

Solución al error con la libreria sassc
error: no such option: --stdin




Solución al Error:
sassc: error: no such option: --stdin

Line 13 in 3c11cf9
libsass==0.12.3

Como verÔn la solución es la versión de la librería.

jueves, 21 de mayo de 2020

Solución al error con Nginx ssl_error_bad_cert_domain

Solución al Error ssl_error_bad_cert_domain


Si tenemos un error al configurar nuestro dominio nginx con letsencrypt se debe a que el certificado ssl requiere expandir a ambas url, para ello ejecutamos el comando:

 letsencrypt certonly --standalone -d midominio.mx -d www.midominio.mx


La configuración de nginx quedaria (midominio.mx) --> /etc/nginx/sites-enabled:

upstream oddo {
    server 127.0.0.1:8069;
}

server {
    listen      443 default;
    server_name midominio.mx www.midominio.mx;

    access_log  /var/log/nginx/oddo.access.log;
    error_log   /var/log/nginx/oddo.error.log;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/midominio.mx/cert.pem;
    ssl_certificate_key /etc/letsencrypt/live/midominio.mx/privkey.pem;
    keepalive_timeout   60;

    #ssl_ciphers             HIGH:!ADH:!MD5;
    #ssl_protocols           SSLv3 TLSv1;
    ssl_prefer_server_ciphers on;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    proxy_buffers 16 64k;
    proxy_buffer_size 128k;

    location / {
        proxy_pass  http://oddo;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_redirect off;

        proxy_set_header    Host            $host;
        proxy_set_header    X-Real-IP       $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header    X-Forwarded-Proto https;
        proxy_read_timeout 300000;

    }

    location ~* /web/static/ {
        proxy_cache_valid 200 60m;
        proxy_buffering on;
        expires 864000;
        proxy_pass http://oddo;
    }
}

server {
    listen      80;
    server_name midominio.mx www.midominio.mx;

    add_header Strict-Transport-Security max-age=2592000;
    rewrite ^/.*$ https://$host$request_uri? permanent;
}

domingo, 29 de marzo de 2020

Presicion Decimal en Odoo 13

Creación de Campos con Decimales Dinamicos




Como habíamos mencionado en post anteriores podemos definir una presicion dinÔmica que nos permita gestionar de forma modificable el no. de decimales para la definición de los campos en una clase.

<?xml version="1.0" encoding="UTF-8"?>
<odoo>
   <data>
  <!--  Mi presicion decimal-->

  <record model="decimal.precision" id="precision_discounts">
    <field name="name">Discount</field>
    <field name="digits">6</field>
  </record>  

   </data>
</odoo>

Al instalar nuestro modulo o actualizarlo, nos creara el registro correspondiente al XML:


El valor digits es el numero de decimales que tendra el campo que lo utilice como su presición decimal.

El paso final es asignar esta presición en la creación del campo en una clase Odoo.

# -*- coding: utf-8 -*-
from openerp.exceptions import UserError
from openerp import api, fields, models, _, tools

class Accountinvoice(models.Model):
    _inherit = 'account.invoice'
    _name = 'account.invoice'
    
    invoice_discount_amount = fields.Float(digits='Discount', 
                                string='Descuento Total en Monto')


En el ejemplo anterior herede facturas y cree mi campo llamado Descuento Total con 6 Decimales en su parte flotante, el campo se visualiza de la siguiente manera en el Sistema:

Si modificamos la presición decimal a 4.


Veriamos el campo actualizado y los registros anteriores redondeados al nuevo numero de decimales.

Una presición puede ser reutilzada muchas veces no es necesario crear una por cada campo a menos que el proceso lo requiera.

Espero que les ayude esta información y no se olviden dejar sus comentarios.




martes, 25 de febrero de 2020

Campo Binario B64 a Archivo Temporal Python

Binario B64 a Archivo Fisico Temporal


Ultimamente me han pedido desarrollar reportes en Excel, para esto me apoyo mucho de la libreria xlsxwriter o del modulo report_xlsx, pero muchas veces es necesario utilizar el logo dentro del reporte, en Qweb seria muy sencillo ya que la utilidad hace la conversión del binario, pero en mi caso no fue asi, existen 2 maneras de hacerlo metiendo la ruta fisica del archivo dentro de nuestro moulo o la segunda la cual vengo a enseñarles, guardar el campo a un archivo temporal, en el siguiente ejemplo cree 2 funciones para guardar el logo dato que requiero para dar formato a mi excel.


import tempfile
import base64
import binascii
import os

class ClaseOdoo(models.Model):
    _name = 'mi.clase'
    _inherit ='mi.clase'

    def b64str_to_tempfile(self, b64_str=None, file_suffix=None, file_prefix=None):
        """
        @param b64_str : Text in Base_64 format for add in the file
        @param file_suffix : Sufix of the file
        @param file_prefix : Name of file in TempFile
        """

        (fileno, fname) = tempfile.mkstemp(file_suffix, file_prefix)
        f = open(fname, 'wb')
        f.write(base64.decodestring(b64_str or ''))
        f.close()
        os.close(fileno)
        return fname



    def logo_b64_str_to_physical_file(self, b64_str, file_extension='png', prefix='company_logo'):

        certificate_lib = self.env['facturae.certificate.library']
        b64_temporal_route = self.b64str_to_tempfile(base64.encodestring(''), 
                                                          file_suffix='.%s' % file_extension, 
                                                          file_prefix='odoo__%s__' % prefix)
        _logger.info("\n### b64_temporal_route %s " % b64_temporal_route)
        ### Guardando el Logo  ###
        f = open(b64_temporal_route, 'wb')
        f.write(base64.b64decode(b64_str))
        f.close()
        file_result = open(b64_temporal_route, 'rb').read()
        return file_result, b64_temporal_route




Como paso final solo necesitamos el fragmento de codigo que llame a estas funciones:


        company_logo = self.env.user.company_id.logo
        print ("###### company_logo >>>>>>> ", company_logo)
        if company_logo:
            file_result_b64, logo_path_b64 = self.logo_b64_str_to_physical_file(company_logo, 'png', 'company_logo')
            print ("#### logo_path_b64 >>>>>>>> ",logo_path_b64)     
            image_module_path = logo_path_b64
        else:
            module_path = module.get_module_path('mi_modulo')
            #print "########## MODULE PATH >>> ",module_path
            image_module_path = module_path+'/static/img/logo.jpg'

miƩrcoles, 19 de febrero de 2020

Debug en Plantillas Qweb

Debug Qweb en Odoo


Como en el desarrollo de modulos y aplicaciones en Odoo podemos también debuggear nuestras plantillas una practica que nos puede llegar a ser muy util para conocer el momento exacto donde se genera o ejecuta una sentencia, funcion o se manada a ejecutar metodos dentro de nuestro reporte, esto nos facilita la resolución de muchos errores.

Lo unico que necesitamos agregar dentro de nuestro reporte es:



<t t-debug="pdb"/>


Con  ello podremos utilizar dentro de nuestro Debug Python con el metodo set_trace(), habilitamos dentro de nuestro registro de eventos el parametro --log-level=debug y por ultimo solo queda depurar nuestra plantilla XML con pdb.

Odoo Qweb manejo de Ciclos

Loops o Ciclos con




QWeb en Odoo es muy util al momento de realizar o ejecutar funcionalidades como Reportes, Archivos XML etc. todo esto basado en plantillas, pero existen muchas funcionalidades muy utiles que nos pueden ayudar a mejorar el diseƱo de nuestros Reportes, de las cuales les vengo a hablar en este post y son:


  • as_first
  • as_last
  • as_index

t t-foreach="['A','B','C','D','E']" t-as="item">
    <p t-if="item_first">
        Inicio
    </p>
    <p>
        Indice <t t-esc="item_index"/> y resultado <t t-esc="item"/>
    </p>
    <p t-if="item_last">
        Fin
    </p>
</t>

El resultado seria:

Inicio
Indice 0 y resultado A
Indice 1 y resultado B
Indice 2 y resultado C
Indice 3 y resultado D
Indice 4 y resultado E
Fin

Podemos deducir que las palabras clave as_first indica el inicio del loop, as_index el recorrido de nuestro ciclo y as_end si es el ultimo valor de nuestra lista.


martes, 18 de febrero de 2020

Acción Automatizada para Prevenir Registros Duplicados

Acción Automaticas Revisión de Registros



     En el Sistema Odoo existe un menu que muy pocos utilizamos debido a que no sabemos realmente como funciona y sobre todo como explotar todo el potencial que tiene para evitar desarrollar restricciones que serian mucho mas faciles registrar dentro de esta Funcionalidad del Sistema.

El menu tiene por nombre Acciones Automaticas o Automatizadas dentro del menu de Configuración de Odoo.


Primero Crearemos un registro nuevo con el nombre que nos permita identificarlo de manera mas facil.

Lo primero seria:
  • Nombre de la Regla o Acción
  • Modelo al cual Aplicar.
  • Ejecución en este caso al Crear y Actualizar.




Lo segundo es generar el Codigo Python que nos va permitir aplicar la regla o restricción, para ello pulsamos dentro de la Pestaña Opciones y agregamos una Acción en Python.


El Código seria:


if record.default_code:
   existing_product = env['product.template'].search(
[('id','!=',record.id),
('default_code','=',record.default_code)
])
   if existing_product:
     raise Warning("La Referencia Interna ya existe en 
                    otro Producto en el Sistema.!")


Espero que les sea de utilidad.