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

jueves, 28 de mayo de 2015

Eliminar los Valores predefinidos por el Usuario

Eliminar los Valores predefinidos por el Usuario


    Es muy común que el administrador del Sistema le aplique un valor predeterminado a un Campo(s), como puede ser detalles en Notas, Referencias, Ubicaciones por default, y cuando queremos Eliminarlas no sabemos en donde se Almacenan.

Ejemplo, yo aplico un texto en Notas con la leyenda: "UNA VEZ SALIDA LA MERCANCÍA NO SE ACEPTAN DEVOLUCIONES, REVÍSELA ANTES DE SALIR DE LA TIENDA" y la defino por default para que cada Factura lleve impresa la misma.


    Si en algún punto de la Empresa decide cambiar y tener garantía en sus productos, esta leyenda ya no sera necesaria, entonces para evitarle al usuario tener que eliminarla cada vez que crea una Factura, debemos eliminar ese valor del Sistema.

Para eliminar campos con valores por defecto, vamos a ir al menú del Sistema Configuración --> Técnico --> Acciones --> Predeterminados Predefinidos por el Usuario.

Aquí solo tendremos que aplicar los filtros para encontrar nuestro campo.


Ahora solo lo seleccionamos y pulsamos Eliminar.




miércoles, 27 de mayo de 2015

Estructura de las Agrupaciones en Vistas Formulario

Col y Colspan


    En Odoo la forma de estructurar y mostrar los Campos para las Vistas Formulario, con un orden especifico y agrupado por ciertos datos, es realizado mediante los atributos col y colspan, básicamente una Vista Formulario esta divida en 4 Secciones, 2 Para los textos de los campos y los otros 2 para sus Valores.

    Por defecto Odoo utiliza una columna para el Texto y 3 para el Valor del Campo, lo que se conoce como colspan="4", si necesitas utilizar una agrupación de 2 campos por linea, utilizamos col="4".

Columnas de un Formulario:

Codigo:
<form>
┌───┬───┬───┬───┐
│ 1 │ 2 │ 3 │ 4 │
└───┴───┴───┴───┘
</form>
Ejemplo de un Grupo col="4", en donde toma 2 columnas para texto y 2 para los Valores.
Codigo:
<group col="4">
    <field name="input" />
    <field name="inpt2" />

</group>
┌───────┬───────┬───────┬───────┐
│ label │ input │ labl2 │ inpt2 │
└───────┴───────┴───────┴───────┘

Ejemplos de Agrupaciones Colspan:
Codigo:
<group>
    <field name="inpt4"/>
</group>

<group col="4">
  <field name="input" />
  <field name="inpt2" />
</group>
┌───────┬───────────────────────┐
│ labl4 │ inpt4_______________  │
├───────┼───────┬───────┬───────┤
│ label │ input │ labl2 │ inpt2 │
└───────┴───────┴───────┴───────┘

<group colspan="1">
   <field name="input" />
</group>
<group colspan="4">
   <field name="inpt4"/>
</group>
<group col="1">
   <field name="inpt2" />
</group>
┌───────┬───────┬───────┬───────┐
│ label │ input │       │       │
├───────┼───────┴───────┴───────┤
│ labl4 │ inpt4_______________  │
├───────┼───────┬───────┬───────┤
│ labl2 │ inpt2 │       │       │
└───────┴───────┴───────┴───────┘

Puedes crear Subgrupos de Campos como en el siguiente Ejemplo:
Codigo:
<group col="2" colspan="2">
   <field name="a" />
   <field name="b" />
</group>
<group col="6" colspan="2">
   <field name="d" />
   <field name="e" />
   <field name="f" />
</group>

 ─

│       │       │                │                │
├───────┴───────┼────────────────┴────────────────┤
│ ┌────┬───┐    │  ┌────┬───┬────┬───┬────┬───┐   │
│ │ lb │ a │    │  │ lb │ d │ lb │ e │ lb │ f │   │
│ ├────┼───┤    │  └────┴───┴────┴───┴────┴───┘   │
│ │ lb │ b │    │                                 │
│ └────┴───┘    │                                 │
├───────┬───────┼────────────────┬────────────────┤
│       │       │                │                │

 ─
Gracias por su Visita!

Corregir el Error de la Zona Horario en Odoo (OpenERP)


Corregir el Error de la Zona Horario en Formularios Odoo (OpenERP




    Muchos Tenemos Errores al momento de generar, Facturas, Pedidos de Venta, Compras, etc..., debido a que Odoo maneja el horario Estándar y aunque se configura la Zona Horaria Correcta para cada usuario, esta no se ve reflejada.

Si tu no encuentras Solución Para este Error, aquí te presento la Solución:

Primero Tenemos que tener Instaladas las librerias:

  • datetime
  • pytz
  • time

Ahora en Odoo importamos estas librerias:
from datetime import date, datetime, timedelta
import time
import pytz

Ahora un ejemplo, primero tomare la fecha actual que me ofrece odoo y la transformare a la Zona Horaria del Usuario Logeado:
date_now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
start = datetime.strptime(date_now, "%Y-%m-%d %H:%M:%S")
user = self.pool.get('res.users').browse(cr, uid, uid)
tz = pytz.timezone(user.tz) if user.tz else pytz.utc
start = pytz.utc.localize(start).astimezone(tz)     
tz_date = start.strftime("%Y-%m-%d %H:%M:%S")
### tz_date es la fecha correcta con la zona hroaria
print "########################## DATE FINAL TZ >>> ", tz_date

Si necesitáramos corregir la fecha y hora de un registro bastaria con hacerlo de la siguiente forma:

for rec in self.browse(cr, uid, ids, context):
    field_date = rec.date ## Campo Fecha del Formulario
    start = datetime.strptime(field_date, "%Y-%m-%d %H:%M:%S")
    user = self.pool.get('res.users').browse(cr, uid, uid)
    tz = pytz.timezone(user.tz) if user.tz else pytz.utc
    start = pytz.utc.localize(start).astimezone(tz)     
    tz_date = start.strftime("%Y-%m-%d %H:%M:%S")
    ### tz_date es la fecha correcta con la zona hroaria
    print "########################## DATE FINAL TZ >>> ", tz_date

Como vimos en el ejemplo anterior, primero obtenemos el valor de campo fecha/fecha_hora, después solo hacemos unas conversiones para pasarlo a la librería pytz.


Espero que les sea de ayuda.



jueves, 7 de mayo de 2015

API ODOO: Metaclases y Decodarores

Implementación de la API de Odoo Utilizando Metaclases y Decoradores



API:

    API por sus siglas en Ingles Application Programming Interface ( Interfaz de Programación de Aplicaciones), es el conjunto de subrutinas, funciones y procedimientos (o métodos, en la programación orientada a objetos) que ofrece cierta biblioteca para ser utilizado por otro software como una capa de abstracción. Son usadas generalmente en las bibliotecas. Fuente: wikipedia.org

Metaclases:

    A metaclase puede definirse como   "Una clase de Clases". En programación orientada a objetos, una metaclase es una clase cuyas instancias son clases. En otras palabras, como los objetos son instancias de una clase, las clases son instancias de una metaclase.

Detalles para Implementar la API en sus Desarrollos:

 Odoo provee 2 formas de Implementar las Clases (Modelos), para la generación de Formularios, podríamos llamarlas como la forma "Tradicional" y a través de "Recordsets". Un recordset es la instancia de una clase, con la referencia del registro en Base de Datos (ID).

    En la forma tradicional utilizamos siempre los parámetros cursor de la base de datos (cr), id usuario (uid), un listado de los Registros (ids) y context, cada vez que definimos un Método de la Clase. Utilizando el método por Recordsets mediante Decoradores, estos parámetros están Implícitos dentro de la API, aquí debemos comprender que si se trabaja con la API de Odoo, todo lo que sea retornado mediante los métodos del ORM siempre serán records.

Ejemplo con el Metodo Tradicional:

    modelo = self.pool.get(Modelo.) # Instanciamos una Clase (Modelo)
    ids = modelo.search(cr, uid, [Dominio con Condiciones para la Busqueda], context=context) 
    # Una funcion search con la forma Tradicional siempre Rertorna una lista de IDS
    for rec in modelo.browse(cr, uid, ids, context=context):
        print rec.name
    modelo.write(cr, uid, ids, {Diccionario de Valores a Actualizar}, context=context)

Ejemplo Utilizando la API de Odoo:

    env = env(cr, uid, context)         # cr, uid, context, implicitos en la instancia env
    recs = env[Modelo]                    # Instanciamos una Clase(Modelo) de Odoo
    recs = recs.search([Dominio con Condiciones para la Busqueda de Registros])          
   #  Una busqueda utilizando env y la API, siempre retornada una lista de Recordsets.
    for rec in recs:                             # Podemos recorrer cada record para poder trabajar con ellos.
        print rec.name
    recs.write({Diccionario de Valores a Actualizar})

Como pudimos observar, los parámetros tradicionales (cr, uid, ids, context) están Implícitos al trabajar con la API de Odoo, algo que puede confundirnos es al momento de trabajar con Ambas.

Decoradores:

Los decoradores en Odoo, son utilizados para tratar de enviar los argumentos que el Sistema sabe que tiene que recibir de forma Obligatoria como el Ejemplo Anterior (cr, uid, ids, context).

Los Decoradores con la API Odoo, nos ayudan a Decorar las funciones tradicionales y a Implementar una nueva Funcionalidad.

Ejemplos:
    
1. @api.cr:

Para decorar funciones que siempre Reciben Como Parametro CR, utilizariamos este Decorador.

    # recs = modelo.browse(cr, uid, ids, context)
    recs.method(args)
    model.method(cr, args)

2. @api.cr_context:

Decoramos Funciones que utilizan siempre 'cr', 'context' como Parametros.
  
3. @api.cr_uid:

Decoramos Funciones que utilizan siempre 'cr', 'uid' como Parametros.

4. @api.cr_uid_context:

Decoramos Funciones que utilizan siempre 'cr', 'uid', 'context' como Parametros. 

    # recs = modelo.browse(cr, uid, ids, context)
    recs.method(args)

    modelo.metodo(cr, uid, args, context=context)

5. @api.cr_uid_id:

Decoramos Funciones que utilizan siempre 'cr', 'uid', 'ids' como Parametros. Podriamos utilizar un Decorador de este tipo para retornar siempre un Recordset sin tener que generar la instancia y pasar los Parametros.


6. @api.cr_uid_id:

Este Ejemplo seria el mas claro si estamos acostumbrados a definir funciones con OpenERP, en donde siempre eran requeridos los parametros 'cr', 'uid', 'id':

    @api.cr_uid_id
    def metodo(self, cr, uid, id, args, context=None):
        ...

7. @api.cr_uid_ids:

Este Decorador seria el mismo que el anterior solo que aquí se enviaría el parámetro IDS con un listado de Registros, en el anterior solo podríamos enviar un solo ID.

8. @api.cr_uid_ids_context:

Este Decorador como su nombre lo describe, recibe todos los parametros para poder generar Funciones. Recibe 'cr', 'uid', 'ids', 'context', parametros que siempre necesitamos para trabajar con Odoo.

Decoradores que utiliza la API de Odoo

1. @api.model:

Este Decorador solo genera una Instancia de una Clase en Odoo (Modelo). Su sintaxis es la siguiente:

    @api.model
    def metodo(self, args):
        ...



2. @api.one:

Este decorador sirve para poder obtener un recordset de la Clase, siempre que sea utilizado en un Metodo. Es equivalente a realizar un browse de una Clase de Odoo (self.browse(cr, uid, id, context=None) ), con este decorador podriamos obtener un valor de esa Clase simplemente con retornar self.campo_a_obtener. Su sintaxis es la siguiente:

    @api.one
    def metodo(self, args):
        return self.name

Con el Método Tradicional Seria:

    def metodo(self, cr, uid, id, context=None):
        inst = self.browse(cr, uid, id, context=None)
        return inst.name

3. @api.multi:

Este Decorador es similar al anterior, solo que aquí retorna un listado de recordsets. Su sintaxis es la siguiente:

    @api.multi
    def method(self, args):
        ...
       

En la forma tradicional seria definir un ciclo con el metodo Browse:
    
    def metodo(self, cr, uid, ids, context=None):
        for rec in self.browse(cr, uid, ids, context=None)
             print "#### Campo Name de cada Registro >>> ", rec.name
        return True

En la forma tradicional solíamos obtener los ids a recorrer usando el método Search.

4. @api.constrains:

Como podemos observar por su nombre, este decorador nos permite decorar funciones para crear Restricciones a la Inserción de Información, los llamados Constraints. Su sintaxis es la siguiente:

    @api.one
    @api.constrains('name', 'description')
    def _check_description(self):
        if self.name == self.description:
            raise ValidationError("Los Campos Nombre y Descripción no pueden ser los Mismos")

Para que quede claro, un ejemplo con la Forma tradicional:

    def _check_description(self, cr, uid, ids, context=None):
        for rec in self.browse(cr, uid, ids, context=None):
            if rec.name == rec.description:
                 return False
         return True

_constraints = [(_check_description, 'Error: Los Campos Nombre y Descripcion No pueden ser Iguales', ['name','description']), ] 

5. @api.onchange:

    Si has llegado a este Decorador ya tienes la idea de lo que ah tratado de hacer Odoo, que es tratar de Optimizar el Código enfocándonos directamente en la lógica del requerimiento, sin tener que ser recurrentes con los parámetros, este Decorador nos sirve para poder crear métodos on_change (Métodos que se ejecutar al cambiar un Valor del Formulario en donde este asignado este Metodo).
Su sintaxis es la siguiente:

    @api.onchange('partner_id')
    def _onchange_partner(self):
        recs = env['res.partner']                    
        recs = recs.search([('parent_id','=',self.partner_id)]) 

        self.partner_id = recs[0].id

Observamos que ahora ya no es necesario retornar Valores en un diccionario del tipo {'value':{Campos a Actualizar}. Observamos que el Decorador recibe parámetros, que en este caso son los campos que necesitamos para poder trabajar como es  'partner_id'.

Ejemplo con la forma Tradicional:
    def _onchange_partner(self, cr, uid, ids, partner_id, context=None):
          partner_id = self.pool.get('res.partner').search(cr, uid, [('parent_id','=',partner_id)], context)
          if partner_id:
               return {'value':{'partner_id': partner_id[0]}}
          return {}

     

6. @api.depends:

Este Decorador es utilizado para campos Calculados, o campos que requieran obtener un listado de valores:

    pname = fields.Char(compute='_compute_pname')

    @api.one
    @api.depends('partner_id.name', 'partner_id.is_company')
    def _compute_pname(self):
        if self.partner_id.is_company:
            self.pname = (self.partner_id.name or "").upper()
        else:
            self.pname = self.partner_id.name

7.@api.returns:

Decorador que permite retornar instancias de un Modelo. Sus sintaxis es:

    @model
    @returns('res.partner') # Modelo a Recibir
    def find_partner(self, arg):
        ...     # retorna algun recordset


Decoradores para Interactuar con los Nuevos estilos utilizando una version Tradicional.

1. @api.v7:

Este Decorador permite utilizar metodos de la Nueva API, generando Clases (Modelos) de la forma Tradicional. Su sintaxis es:

    @api.v7
    def foo(self, cr, uid, ids, context=None):
        ...

    @api.v8
    def foo(self):
        ...


Decoradores para Interactuar con el estilo Tradicional utilizando una version con la nueva API.

1. @api.v8:

    @api.v8
    def foo(self):
        ...

    @api.v7
    def foo(self, cr, uid, ids, context=None):
        ...

Espero que les pueda ayudar a comprender la nueva API, aun me faltan muchas cosas por Comprender que estaré subiendo.