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

martes, 1 de diciembre de 2015

ODOO V8 API: Decorator and Metaclass Part 2

ODOO V8 API: Everything about Decorator and Metaclass

2014-11-15 20:10:10

API

An API(Application Programming Interface) is a set of defined functions and procedures that allow the creation of applications which access the features or data of an operating system, application, or other service. (Source Google)

Metaclass

A metaclass is defined as "the class of a class". Any class whose instances are themselves classes, is a metaclass. (Source wikipedia)

Some Explanations what we can do with metaclass

  • Enforce different inheritance semantics, e.g. automatically call base class methods when a derived class overrides.
  • Implement class methods (e.g. if the first argument is not named 'self') for precondition and post-condition checking.
  • Implement that each instance is initialized with copies of all class variables.
  • Implement a different way to store instance variables (e.g. in a list kept outside the the instance but indexed by the instance's id()).
  • Automatically wrap or trap all or certain methods:
  • Used for tracing
  • Used for precondition and post-condition checking
  • Used for synchronized methods
  • Used for automatic value caching

Metaclass's new and init:

To control the creation and initialization of the class in the metaclass, you can implement the metaclass's new method and/or init constructor. Most real-life metaclasses will probably override just one of them. new should be implemented when you want to control the creation of a new object (class in our case), and init should be implemented when you want to control the initialization of the new object after it has been created.

Features of New API

Api is bridge filling the gap between old "traditional" and new "record" style
In old traditional style , Parameter like database cursor, user id, context dictionary, and record are manually passed in the function in the form of parameters such as (cr, uid, ids, context) Example
model = self.pool.get(MODEL)
ids = model.search(cr, uid, DOMAIN, context=context)
for rec in model.browse(cr, uid, ids, context=context):
print rec.name
model.write(cr, uid, ids, VALUES, context=context)
In new API style those are hidden into model instances, which gives it more pythonic and object-oriented feel. which can be access as (self.cr, self.uid ..)
example above(old style)can be written as:
recs = self.env[MODEL] # retrieve an instance of MODEL
recs = recs.search(DOMAIN) # search returns a recordset
for rec in recs: # iterate over the records
print rec.name
recs.write(VALUES) # update all records in recs
Methods written in the "traditional" style are automatically decorated, following some heuristics based on parameter names.

Meta classes

class Meta(type): It is used to automatically decorates traditional-style methods by guessing their API. It also implements the inheritance of the :func:'returns' decorators.
Metaclass's __new:__ It is used to automatically decorates traditional-style methods by guessing their API.

Decorator's

A decorator is just a callable that takes a function as an argument and returns a replacement function
The Decorator's which is used to decorate the traditional-style method:
@api.cr: Decorate a traditional-style method that takes 'cr' as a parameter. Such a method may be called in both record and traditional styles, like:
@api.cr_context: Decorate a traditional-style method that takes 'cr', 'context' as parameters.
@api.cr_uid: Decorate a traditional-style method that takes 'cr', 'uid' as parameters.
@api.cr_uid_context: Decorate a traditional-style method that takes 'cr', 'uid', 'context' as parameters. Such a method may be called in both record and traditional styles, like:
recs.method(args) model.method(cr, uid, args, context=context)
@api.cr_uid_ids: Decorate a traditional-style method that takes 'cr', 'uid', 'ids' as parameters. Such a method may be called in both record and traditional styles. In the record style, the method automatically loops on records.
@api.cr_uid_id_context: Decorate a traditional-style method that takes 'cr', 'uid', 'id', 'context' as parameters. Such a method:
@api.cr_uid_ids_context: Decorate a traditional-style method that takes 'cr', 'uid', 'ids', 'context' as parameters. Such a method:
The Decorator's which is used to decorate the new record-style method:
@api.model: Decorate a record-style method where 'self' is a recordset, but its contents is not relevant, only the model is. Such a method:
@api.model
def method(self, args):
    ...
may be called in both record and traditional styles, like:
# recs = model.browse(cr, uid, ids, context)
recs.method(args)

model.method(cr, uid, args, context=context)
Notice that no 'ids' are passed to the method in the traditional style.
@api.one: Decorate a record-style method where 'self' is expected to be a singleton instance. The decorated method automatically loops on records, and makes a list with the results. In case the method is decorated with @returns, it concatenates the resulting instances. Such a method:
@api.one
def method(self, args):
    return self.name
may be called in both record and traditional styles, like::
# recs = model.browse(cr, uid, ids, context)
names = recs.method(args)

names = model.method(cr, uid, ids, args, context=context)
Each time 'self' is redefined as current record.
@api.multi: Decorate a record-style method where 'self' is a recordset. The method typically defines an operation on records. Such a method:
@api.multi
def method(self, args):
    ...
may be called in both record and traditional styles, like::
# recs = model.browse(cr, uid, ids, context)
recs.method(args)

model.method(cr, uid, ids, args, context=context)
@api.constrains: Decorates a constraint checker. Each argument must be a field name used in the check:
@api.one
@api.constrains('name', 'description')
def _check_description(self):
    if self.name == self.description:
        raise ValidationError("Fields name and description must be different")
Invoked on the records on which one of the named fields has been modified.
Should raise :class:'~openerp.exceptions.ValidationError' if the validation failed.
@api.onchange: Return a decorator to decorate an onchange method for given fields. Each argument must be a field name:
@api.onchange('partner_id')
def _onchange_partner(self):
    self.message = "Dear %s" % (self.partner_id.name or "")
In the form views where the field appears, the method will be called when one of the given fields is modified. The method is invoked on a pseudo-record that contains the values present in the form. Field assignments on that record are automatically sent back to the client.
@api.depends: Return a decorator that specifies the field dependencies of a "compute" method (for new-style function fields). Each argument must be a string that consists in a dot-separated sequence of field names:
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
One may also pass a single function as argument. In that case, the dependencies are given by calling the function with the field's model.
@api.returns: Return a decorator for methods that return instances of 'model'.
:param model: a model name, or 'self' for the current model

:param downgrade: a function 'downgrade(value)' to convert the
    record-style 'value' to a traditional-style output
The decorator adapts the method output to the api style: 'id', 'ids' or 'False' for the traditional style, and recordset for the record style:
@model
@returns('res.partner')
def find_partner(self, arg):
    ...     # return some record

# output depends on call style: traditional vs record style
partner_id = model.find_partner(cr, uid, arg, context=context)

# recs = model.browse(cr, uid, ids, context)
partner_record = recs.find_partner(arg)
Note that the decorated method must satisfy that convention.
Those decorators are automatically inherited: a method that overrides a decorated existing method will be decorated with the same '@returns(model)'.
The Decorator's which is used to decorate a method that supports the old-style API only:
  1. @api.v7:
Decorate a method that supports the old-style api only. A new-style api may be provided by redefining a method with the same name and decorated with :func:'~.v8':
@api.v7
def foo(self, cr, uid, ids, context=None):
    ...

@api.v8
def foo(self):
    ...
Note that the wrapper method uses the docstring of the first method.
The Decorator's which is used to decorate a method that supports the new-style API only:
  1. @api.v8:
Decorate a method that supports the new-style api only. An old-style api may be provided by redefining a method with the same name and decorated with :func:'~.v7':
@api.v8
def foo(self):
    ...

@api.v7
def foo(self, cr, uid, ids, context=None):
    ...
Note that the wrapper method uses the docstring of the first method.

viernes, 27 de noviembre de 2015

Script Instalar o Desinstalar modulo con la librerĆ­a OERPLIB de forma externa a Odoo

Desinstalar o Instalar un modulo desde Python mediante un Script


Para el desarrollo de este Script, utilizaremos la librerĆ­a oerplib, si utilizamos Ubuntu o Linux podemos descargar con el comando:

sudo pip install oerplib 

El código es el siguiente:

import oerplib

user = 'admin' # Usuario de la Base de datos 
passwd = 'admin' # ContraseƱa del Usuario de la Base de datos.
port = 8069 # Puerto en el que esta ejecutandose Odoo por default es el 8069
name_db = 'Base_Demo' # Nombre de la Base de Datos
module = 'modulo_desinstalar' # Modulo a Desinstalar

oerp = oerplib.OERP(server='localhost',protocol='xmlrpc',port=port)
oerp.login(user, passwd, database=name_db)
module_obj = oerp.get('ir.module.module')
module_id = module_obj.search([('name', '=', module)])

operacion = True
while(operacion):
    resp = raw_input('Que operacion necesita:\nInstalar modulo %s, Desinstalar modulo %s o Salir? i/d/s:'%(module,module))
    if resp == 'd':
        module_obj.button_immediate_uninstall(module_id)
    elif resp == 'i':
        module_obj.button_immediate_install(module_id)
    else:
        operacion = False

Lo único que necesitamos es guardarlo con un nombre y la extensión .py, para ejecutarlo basta con abrir una terminal, ubicarnos en la dura donde guardamos el script y ejecutar:

python script_instalacion.py


Script SQL Autocorreccion de Margenes

Corrección de Margenes Negativos o erróneos a partir de SQL



update sale_order set margin = amount_untaxed-(select sum(sol.purchase_price*sol.product_uos_qty) 
   from sale_order_line as sol join sale_order as so on so.id = sol.order_id and so.id=sale_order.id)

jueves, 26 de noviembre de 2015

Odoo POS Pop Ups

Odoo POS Pop Ups

In odoo retailers will be mostly concentrating on POS because that minimizes their effort to more extreme,….
Now on developer side it is tough work to customize that pos.. since it is collaboration of js, jquery with python…  Some times head ache.. :P :) ..
No problem now we will see how to create a pop up in odoo POS,,,,
For this you need some basic knowledge in
1) js, jquery
2)python
3)odoo qweb widgets
Now we are going to create a popup asking name to enter in pos….
create a module in odoo.. with init and openerp file…
Now normally on creation of wizard we used to create a form for pop right.. like that create one as below..
create model.py file with following code:
from openerp import api, fields, models
from openerp.osv import osv
class pos_model(models.Model):
_name = ‘pos.popup’
name=fields.Char(‘Name’,size=30,required=True)
def okay_refresh(self,cr,uid,ids,context=None):
return{
‘type’:’ir.actions.client’,
‘tag’:’reload’,
}
view.xml file has this:
<?xml version=”1.0″ encoding=”utf-8″?>
<openerp>
<data>
<record model=”ir.actions.act_window” id=”create_pop_up”>
<field name=”name”>Pop up</field>
<field name=”res_model”>pos.popup</field>
<field name=”view_mode”>form</field>
</record>
<record id=”create_pop_form” model=”ir.ui.view”>
<field name=”name”>Pop up</field>
<field name=”model”>pos.popup</field>
<field name=”type”>form</field>
<field name=”arch” type=”xml”>
<form string=”Pop up” version=”7.0″>
<br />
<h2>Enter the name:</h2>
<br /><br />
<label for=”name” style=”clear:left;text-align:right;padding-right:10px;float:left;padding-left:5em “/>
<field name=”name” nolable=”1″ style=”float:left;padding-left:5em “/><br /><br />
<br />
<br />
<div style=”align:center;float:left;padding-left:12em “>
<button name=”ok_refresh” type=”object” string=”Okay”/>
</div>
</form>
</field>
</record>
Now its turn for POS module change..
TO add button to POS.. create static–>src–>xml–>pop_up.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<template id=”payment_screen”>
<t t-extend=”PosWidget”>
<t t-jquery=”div.pos-branding” t-operation=”inner”>
<button class=”popup-misc” style=”position:absolute;left:300px; top:7px;width: 100px; height: 37px; font-size:15px;”>Name popup</button>
</t>
</t>
</template>
Now create a file static–>src–>js–>pos_pop.js
in that paste it
openerp.module_name = function(instance){
var module = instance.point_of_sale; 
var QWeb = instance.web.qweb;
module.PosWidget.include({
build_widgets: function(){
var self = this;
this._super();
this.$el.find(‘.popup-misc’).click(function(){
self.do_action({
type: ‘ir.actions.act_window’,
res_model: “pos.popup”,
views: [[false, ‘form’]],
target: ‘new’,
context: {},
});
});
}
});
};
create a file template.xml in that paste the following code
<openerp>
<data>
<template id=”assets_frontend” inherit_id=”web.assets_common”>
<xpath expr=”.” position=”inside”>
<script type=”text/javascript” src=”/module_name/static/src/js/pos_pop.js”></script>
</xpath>
</template>
</data>
</openerp>
This will add your js to odoo frond end..
Finally add all the xml files in _openerp__.py…

lunes, 23 de noviembre de 2015

Crear un Complemento en Odoo

En esta ocasión les comparto un tema de un error que probablemente a algunos les haya salido al momento de intentar validar una factura electrónica CFD o CFDI con los xsd publicados en el SAT

El error podrĆ” venir en la forma :

 No matching global element declaration available, but demanded by the strict wildcard  

En mi ejemplo me mandaba
 Element '{http://www.sat.gob.mx/ventavehiculos}VentaVehiculos': No matching global element declaration available, but demanded by the strict wildcard  

El xml el que estaba validando simplemente tenĆ­a lo siguiente :

El sat en realidad no define dentro del xsd  de cfd v2.2 el nodo ventavehiculos, tal es el caso que aunque se declarara el namespace y schemalocation dentro de ese nodo al intentar validarlo del primer nodo mandaba error en algunos validadores, ya que el xsd de ventavehiculos se encuentra en otro archivo diferente
Si queremos validar un XML del SAT que contenga nodos que son opcionales para el SAT tendremos que bajar el xsd de cfd o cfdi vigente y hacer un import dentro del mismo a los xsd opcionales o tambiĆ©n agregar los xsd que ustedes por ejemplo ocupen para la sección addenda

1:  <xs:schema xmlns="http://www.sat.gob.mx/cfd/2" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:psgecfd="http://www.sat.gob.mx/psgecfd" xmlns:donat="http://www.sat.gob.mx/donat" xmlns:divisas="http://www.sat.gob.mx/divisas" xmlns:ecc="http://www.sat.gob.mx/ecc" xmlns:ecb="http://www.sat.gob.mx/ecb" xmlns:ecfd="http://www.southconsulting.com/schemas/strict" xmlns:detallista="http://www.sat.gob.mx/detallista" xmlns:implocal="http://www.sat.gob.mx/implocal" xmlns:terceros="http://www.sat.gob.mx/terceros" targetNamespace="http://www.sat.gob.mx/cfd/2" elementFormDefault="qualified" attributeFormDefault="unqualified">  
2:       <xs:import namespace="http://www.sat.gob.mx/psgecfd" schemaLocation="psgecfd.xsd"/>  
3:       <xs:import namespace="http://www.sat.gob.mx/donat" schemaLocation="donat11.xsd"/>  
4:       <xs:import namespace="http://www.sat.gob.mx/divisas" schemaLocation="Divisas.xsd"/>  
5:       <xs:import namespace="http://www.sat.gob.mx/ecc" schemaLocation="ecc.xsd"/>  
6:       <xs:import namespace="http://www.sat.gob.mx/ecb" schemaLocation="ecb.xsd"/>  
7:       <xs:import namespace="http://www.southconsulting.com/schemas/strict" schemaLocation="ecfd.xsd"/>  
8:       <xs:include schemaLocation="INVOIC-VITRO2010.xsd"/>  
9:       <xs:import namespace="http://www.sat.gob.mx/detallista" schemaLocation="detallista.xsd"/>  
10:       <xs:import namespace="http://www.sat.gob.mx/implocal" schemaLocation="implocal.xsd"/>  
11:       <xs:import namespace="http://www.sat.gob.mx/terceros" schemaLocation="terceros11.xsd"/>  
12:       <xs:import namespace="http://www.sat.gob.mx/ventavehiculos" schemaLocation="ventavehiculos.xsd"/>  
13:       <xs:element name="Comprobante">  

miƩrcoles, 18 de noviembre de 2015

Actualizar campos a partir de una segunda Tabla en PostreSQL

Actualización entre Tablas PostgreSQL


Postgres es una herramienta super poderosa te permite manipular una infinidad de datos en tiempos muy cortos, aprovechando este administrador de bases de datos podemos actualizar registros a una velocidad superior de una tabla a otra con un query bastante sencillo, este ejemplo que les voy a compartir actualiza el campo Empresa de la tabla account_move a partir de la tabla account_move_line:

UPDATE account_move SET partner_id=account_move_line.partner_id FROM account_move_line 
WHERE account_move_line.move_id=account_move.id and account_move.partner_id is null 

miƩrcoles, 21 de octubre de 2015

Enviar Mensajes al Archivo Log de Odoo



Logging


    Muchas veces programamos en odoo y la mejor manera de hacer un debug es enviando prints con python y estos se muestran en la terminal, pero esta tĆ©cnica solo funciona cuando no utilizamos un archivo que guarde el log del Servidor.
    En caso necesario de que necesitemos estar analizando el comportamiento de alguna función en un Servidor de Producción, podemos hacer uso de la libreria loggin, la cual te permite enviar mensajes al logfile (Archivo Log).
1. Importando libreria logging
Esta libreria es propia de Python no de Odoo y funciona con cualquier aplicación hecha en ese mismo Lenguaje de Programación.
1. #Importamos la libreria logger
2. import logging
3. #Definimos la Variable Global
4. _logger = logging.getLogger(__name__)

2. Usamos la libreria loggin para enviar los mensajes.

Para la librerƭa loggin existen 5 mƩtodos de enviar los mensajes al log:
  • logger.debug: Utilizado para el modo debug.
  • logger.info: Este metodo es el mas utilizado, para enviar información al log como si se tratara de un print.
  • logger.warning: Como su nombre lo indica para enviar un mensaje de Advertencia.
  • logger.error:  Utilizado en errores causados por configuraciónes, no poder actualizar algun registro, etc..
  • logger.critical: Este modo de mensaje es para alertar de un fallo total de la Aplicación.
Ejemplos :
1. _logger.debug("Mensaje Debug")
2. _logger.info("Mensaje Informativo o Print")
3. _logger.warning("Mensaje de Advertencia")
4. _logger.error("Mensaje de Error, fallo menor.")
5. _logger.critical("Mensaje con un Error Fatal.")

Logging output terminal

viernes, 16 de octubre de 2015

Solucion a la Impresion sin Estilos de Reportes Qweb (WkhtmltoPdf, Css, Formato,etc..)

Solución a la Impresión de Reportes Qweb sin Estilos


    Hoy quiero hacer mención a un error que nunca me habĆ­a sucedido y que me tenia frustrado pase varios dĆ­as investigando para encontrar la solución, el error sucedĆ­a en la impresión de reportes hechos con Qweb estos se generaban sin formato y sin estilo, al principio como todo analista trate de identificar el Problema, primero probando la versión de la librerĆ­a Wkhtmltopdf, esto sin tener ningĆŗn Ć©xito, segundo revisando y borrando archivos temporales, cache del servidor, etc. Buscando en foros, grupos y demĆ”s encontrĆ© parte de la solución y revisando el código del modulo report complemente la solución final.


La imagen anterior muestra la salida de mi reportes Qweb, como observamos no tiene Estilos.

La solución.

Existen 2 formas de solucionar este error:

1. Modificando el ParĆ”metro del Sistema llamado web.base.url  y verificar que en el valor no usemos un alias o una ip diferente a localhost.

En caso de que tengan un alias como la imagen anterior http://poncesoft.noip.com:9069 debemos cambiarla por http://localhost:9069.

2. La segunda forma de solucionar este error es aƱadiendo un nuevo parĆ”metro llamado report.url  y con el valor mencionado anteriormente http://localhost:9069.
Estos parĆ”metros indican al sistema la dirección fĆ­sica para tomar los estilos del reporte.

Resultado Final:


Nota: Los parĆ”metros del Sistema estĆ”n ubicados en Configuración --> ParĆ”metros --> ParĆ”metros del Sistema.





miƩrcoles, 7 de octubre de 2015

Modificar Acciones para agregar o Reemplazar Atributos

Modificar Acciones en Odoo desde XML



    En odoo muchas veces necesitamos poner algĆŗn filtro nuevo creado por nosotros y usarlo por defecto en acciones creadas por algĆŗn otro modulo, esto es muy sencillo simplemente usamos el atributo ID como referencia,  este tipo de "herencia" se compone del nombre del modulo que contiene el registro, seguido de un punto y el ID de la acción.

Ejemplo:

 <record id="stock.action_move_form2" model="ir.actions.act_window">
            <field name="context">{'search_default_consulta': 1}</field>
</record>



lunes, 5 de octubre de 2015

Imprimir 0.0 cuando el valor es Nulo en Jasper Reports

Print 0.0 when null in Jasper Reports



    Al crear reportes con Jasper Reports un problema muy frecuente era poner el valor 0.0 para campos float, despuĆ©s de buscar y probar las soluciones ofrecidas en foros, en la documentación de Jasper Reports, nunca encontrĆ© una solución real. Pensando y probando con las caracterĆ­sticas que ofrece iReport encontrĆ© una solución muy sencilla, los pasos son muy simples y los describo a continuación:

1. Primero debemos dejar los campos Double o Float de tipo String, no cambiarlo al tipo de dato correcto.

2. Añadimos el campo al reporte y modificamos el campo Text Field Expression, para convertir el campo a Double de forma manual y en caso de que sea null, retornar null sin ningún error.

( $F{Field-field0}.isEmpty() ? null : Double.parseDouble($F{Field-field0}) )


Modificamos el campo Expression Class para retornar el tipo de dato correcto:

java.lang.Double

Nota: La conversión a Double te permitirÔ usar la propiedad Pattern y dar formato al campo Double (Currency, # Decimals, etc.)

3. Al campo anterior activar el Campo Blank when null, para que no ponga nigĆŗn texto null en nuestro PDF.


4. AƱadir al reporte un elemento Static Text Field y poner el valor que deseamos que ponga cuando el campo sea 0.0 o null, en mi caso quiero que ponga $ 0.0


5. Para el Texto anterior activaremos el campo Print When Expression, añadiendo la expresión:

$F{Field-field0}.isEmpty()


Esto harĆ” que cuando el campo sea nulo escriba nuestro Texto y en caso contrario el valor correcto del Campo.

6. Lo Ćŗnico que haremos es encimar los 2 campos, uno encima del otro, asĆ­  el Reporteador pondra un valor u otro cuando tengamos un valor null.


Espero que esta información los ayude tanto como a mi.