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.

Asesoria Especializada

Consultoria desde $15 USD por Hora.

Publicidad

miércoles, 30 de diciembre de 2015

Instalacion de Odoo 8 en CentOS 7


Instalación de Odoo 8 en 
CentOS 7

Instalación de Odoo 8 en un servidor CentOS 7 con GitHub

Instalación y Configuración de PostgreSQL 9.3

Primero que nada debemos instalar y descargar PostgreSQL del repositorio Oficial:
rpm -Uvh http://yum.postgresql.org/9.3/redhat/rhel-7-x86_64/pgdg-centos93-9.3-1.noarch.rpm  
yum -y install postgresql93 postgresql93-server postgresql93-devel --disablerepo=* --enablerepo=pgdg93  
El segundo paso es habilitar el Servidor PostgreSQL como un servicio del Sistema:
/usr/pgsql-9.3/bin/postgresql93-setup initdb
systemctl enable postgresql-9.3.service  
systemctl start postgresql-9.3  
Creamos un usuario postgres para nuestro servidor Odoo:
su - postgres -c "createuser -s odoo" 2> /dev/null || true  

Instalación de dependencias para Odoo

Necesitaremos instalar las herramientas necesarias:
yum -y groupinstall "Development tools"  
Para la instalación de las dependencias ejecutaremos en una terminal:
yum -y install zlib-devel bzip2-devel openssl openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel libpcap-devel xz-devel git libpng libjpeg libXext curl xorg-x11-font-utils fontconfig python-virtualenv libevent-devel libxml2-devel libxslt-devel openldap-devel openjpeg-devel freetype-devel libjpeg-turbo-devel libtiff-devel kernel-devel  
Habilitaremos repositorios como EPEL:
wget http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm  
rpm -ivh epel-release-7-5.noarch.rpm  
Instalacion de Wkhtmltopdf:
yum --enablerepo=epel install wkhtmltopdf  
Instalación de la aplicación Python Pip, para el manejo de las librerías en Python:
yum --enablerepo=epel install python-pip  

Descarga de Odoo desde Repositorios Oficiales via GitHub

Clonamos el repositorio oficial en la ruta /opt/ :
git clone --branch 8.0 https://www.github.com/odoo/odoo /opt/odoo

Creación de una Virtual Env para Odoo

Un virtual env es un emulador de librerías Python, que nos permitirá manejar librerías Python de forma independiente en una ruta especifica.

Creamos un nuevo usuario del Sistema, y lo asignamos como propietario de nuestro git clone Odoo /opt/directorio_odoo :
useradd odoo  
chown -R odoo: /opt/odoo  
su - odoo  
Ahora instalaremos las dependencias desde nuestro archivo requirements.txt, ubicado en la instalación de Odoo (requirements.txt):
/bin/virtualenv odoo
source odoo/bin/activate  
PATH=$PATH:/usr/pgsql-9.3/bin  
pip install -r /opt/odoo/requirements.txt  
exit  
Esperamos que finalice la descarga de los paquetes a nuestro entorno virtual.

Creacion del Servicio Odoo (Systemctl)

Generamos el archivo odoo-server.conf:
cat > /etc/odoo-server.conf << EOF  
[options]
admin_passwd = admin  
db_host = False  
db_port = False  
db_user = odoo  
db_password = False  
addons_path = /opt/odoo/addons  
without-demo=all  
no-xmlrpc = True  
no-xmlrpcs = True  
no-netrpc = True  
log_db = False  
log_handler = ['[\'["[\\\':INFO\\\']"]\']']  
log_level = info  
logfile = False  
login_message = False  
logrotate = True  
syslog = False  
EOF  

Generamos el archivo odoo.service (systemctl):

cat > /usr/lib/systemd/system/odoo.service << EOF  
[Unit]
Description=Odoo 8.0 ERP and CRM server  
After=postgresql-9.3.service

[Service]
Type=simple  
User=odoo  
Group=odoo  
ExecStart=/home/odoo/odoo/bin/python /opt/odoo/openerp-server --config=/etc/odoo-server.conf

[Install]
WantedBy=multi-user.target  
EOF  
Puedes usar el siguiente comando para visualizar el log de Odoo en tiempo real: journalctl -f -u odoo.

Pasos Finales

Necesitamos permitir el acceso de información del puerto 8069 en el firewall de CentOS:
firewall-cmd --zone=public --add-port=8069/tcp --permanent  
firewall-cmd --reload  
Finalmente iniciamos el Servicio de Odoo con los comandos:
systemctl enable odoo.service  
systemctl start odoo  
Listo, ahora visualizaremos en nuestro navegador: http://<ip_servidor>:8069


jueves, 24 de diciembre de 2015

Solucion Definitiva a errores Encoding UTF-8 en codigo Python

Solución a cualquier error UTF-8 en la Interfaz Odoo


    Muchas veces en la programación Python, podemos tener errores al momento de cargar Etiquetas de Campos en las Vistas Odoo, esto debido al uso de caracteres especiales en la escritura Latina, la solución es muy sencilla en el encabezado de nuestros archivos fuente (Python files), debemos cargar la librería sys y hacer un reload con la encodificación UTF-8.

import sys
reload(sys)  
sys.setdefaultencoding('utf8')

Unir Archivos PDF en uno solo desde Python

Unir Archivos PDF con la librería PyPdf


Esto nos puede servir para retornar un archivo PDF con la unión de varios reportes a la vez.


# Cargamos la libreria
from pyPdf import PdfFileWriter, PdfFileReader

# Creamos una funcion que automatice la union de los archivos pdf
def append_pdf(input,output):
    [output.addPage(input.getPage(page_num)) for page_num in range(input.numPages)]

# Instanciamos la escritura de archivos PDF de la libreria pypdf
output = PdfFileWriter()

# Añadimos los reportes, estos podemos cargarlos desde archivos temporales
append_pdf(PdfFileReader(file("Reporte01.pdf","rb")),output)
append_pdf(PdfFileReader(file("Reporte02.pdf","rb")),output)

# Escribimos la Salida Final del Reporte
output.write(file("UnionFinalPDF.pdf","wb"))

Felices Fiestas!!! 

martes, 15 de diciembre de 2015

Herencia de Acciones en Odoo

Heredar Acciones de Ventana en Odoo



La Herencia de acciones de ventana es similar a heredar Vistas, la estructura es la siguiente:


<record id="module_name.record_id" model="campo">
    <field name="campo">Nuevo Valor del Campo</field>
</record>

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">