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

jueves, 30 de julio de 2015

Eliminacion en Cascada y Restricciones en campos Many2One

Eliminacion en Cascada y Restricciones en campos Many2One

    Un Error muy común durante la programación de clases y en especial al utilizar los campos Many2One y One2Many en Odoo es la definición de los atributos.
Existe uno en especial llamado "ondelete", este atributo tiene 3 funciones:

  1. Cascade. Permite eliminar los registros ligados a una clase, cuando tiene un campo one2many.
  2. Restrict. Impide la eliminación de la fila referenciada. 
  3. Set null. Modifica el campo a Nulo ó False, cuando el registro de la relación sea Eliminado.

Un ejemplo de ondelete:

class ejemplo_clase(osv.osv):
    _name = 'ejemplo.clase'
    _description = 'Descripcion del Modelo'
    _columns = {
        'lineas': fields.one2many('ref_id','ejemplo.linea', 'Linea'),
    }

class ejemplo_linea(osv.osv):
    _name = 'ejemplo.linea'
    _description = 'Descripcion del Modelo'
    _columns = {
        'ref_id': fields.many2one('ejemplo.clase', 'Referencia', ondelete="cascade"),
    }

    Lo que pasara en el ejemplo anterior es que cuando se borre un registro de la tabla ejemplo_clase, se borraran los registros de la tabla ejemplo_linea que tenga asignados.


jueves, 16 de julio de 2015

Mostrar Columnas Ocultas en Clases Odoo

Agregar Columnas Ocultas en Vistas Odoo


    En Odoo, por defecto cada vez que se crea una nueva Clase, esta se convierte a una tabla de nuestra Base de Datos, este proceso es administrado por el ORM del Framework, durante esta conversión el sistema creara 5 columnas de forma automática:


  1. id: Este Campo es la llave principal de todas las Tablas.
  2. create_uid: Usuario que creo un registro.
  3. create_date: Fecha en la que se creó el registro.
  4. write_uid: Usuario que modifico un registró.
  5. write_date: Fecha en la que se modifico el registró.
    Las columnas anteriores, sirven de alguna manera para auditar la información, en ocasiones es necesario alguna de estas Columnas en nuestras vistas, pero como son manejadas internamente por el Framework, por defecto no podemos agregarlas directamente.

Para Añadirlas a una vista, se debe hacer lo siguiente:

1. Heredar la Clase y añadir las columnas como campos, teniendo cuidado de definir el tipo exacto como esta en la Tabla:


class mi_clase(osv.osv):
_name='mi.clase'
_columns={
    'create_uid': fields.many2one('res.users', 'Creado Por', readonly=True),
}

mi_clase()

2. Lo ultimo es añadirlo a nuestra Vista ó Vistas:

<record model='ir.ui.view' id='mi_clase_form'>
    <field name='priority'>3</field>
    <field name='type'>form</field>
    <field name='model'>mi.clase</field>
    <field name='arch' type='xml'>
    <form string="Clase Ejemplo">
        <field name="create_uid"/></field>
    </form>
</record>




Instalacion de Odoo desde Repositorios Linux

INSTALACIÓN DE ODOO EN 3 PASOS



Pasos:

1. Abrimos una Terminal, en ubuntu presionamos las teclas Alt+Ctrl+T y nos logeamos como root

2.  Ejecutamos wget -O - https://nightly.odoo.com/odoo.key | apt-key add -
echo "deb http://nightly.odoo.com/8.0/nightly/deb/ ./" >> /etc/apt/sources.list

3. Tecleamos apt-get update && apt-get install odoo.


Listo, tenemos Odo corriendo en el puerto 8069.





viernes, 3 de julio de 2015

Herencia Reportes Qweb en Odoo

Herencia Templates Qweb

    Algó muy útil y necesario para el desarrollo Odoo es la herencia, en mas de una ocasión esto nos ah salvado y ayudado para adaptar el Sistema, Qweb Reports no se queda atras e implementa la herencia de las Vistas que son las que generan nuestros Reportes, para elló utilizaremos la herramienta xml Xpath.

    La forma de  heredar es simple, utilizaremos el ID de la vista del reporte, tal cual lo hacemos con las Vistas de Formulatios y añadimos, modificamos ó reemplazamos un elemento.

Ejemplo Herencia Xpath en Qweb Reports

Vamos a heredar el reporte de Albaran y modificar el cuerpo del Reporte, por ejemplo añadimos una tabla para tener un espacio para firmar la entrada y salida de Almacen.

El codigo para añadir estas firmas es:

<table border="0" style="border-collapse:collapse;color:000000;width:100%" cellpadding="3" cellspacing="3">
    <tr>
        <td  class="text-center" >________________________</td>
        <td  class="text-center" >________________________</td>
    </tr>
    <tr >
         <td class="text-center" >
             <strong>Nombre y Firma Entrega</strong>
         </td>
     <td class="text-center" >
          <strong>Nombre y Firma Recepcion</strong>
      </td>
                            
     </tr>
</table>

Heredamos la vista Qweb por medio del ID:

<template id="report_header_custom" inherit_id="stock.report_picking">
    <xpath expr="//div[@class='page']" position="replace">
        <div class="page">
            Aquí va nuestro código .......
        </div>
    </xpath>
 </template>

Al final  así quedo mi  nueva Vista para el Reporte de Albarán:

<!-- Template Final -->
    <template id="report_header_custom" inherit_id="stock.report_picking">
            <xpath expr="//div[@class='page']" position="replace">
                <div class="page">
                    <div class="row"><div class="col-xs-4 pull-right">
                    <img t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s' % ('Code128', o.name, 600, 100)" style="width:300px;height:50px;"/>
                    </div></div>
                    <div class="row">
                        <div class="col-xs-6">
                            <div t-if="o.picking_type_id.code=='incoming' and o.partner_id">
                                <span><strong>Supplier Address:</strong></span>
                            </div>
                            <div t-if="o.picking_type_id.code=='internal' and o.partner_id">
                                <span><strong>Warehouse Address:</strong></span>
                            </div>
                            <div t-if="o.picking_type_id.code=='outgoing' and o.partner_id">
                                <span><strong>Customer Address:</strong></span>
                            </div>
                            <div t-if="o.partner_id" name="partner_header">
                                <div t-field="o.partner_id" t-field-options="{&quot;widget&quot;: &quot;contact&quot;, &quot;fields&quot;: [&quot;address&quot;, &quot;name&quot;, &quot;phone&quot;, &quot;fax&quot;], &quot;no_marker&quot;: true}"/>
                                <p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
                            </div>
                        </div>
                        <div class="col-xs-5 col-xs-offset-1">
                            <div t-if="o.move_lines and o.move_lines[0].partner_id and o.move_lines[0].partner_id.id != o.partner_id.id">
                                <span><strong>Delivery Address:</strong></span>
                                <div t-field="o.move_lines[0].partner_id" t-field-options="{&quot;widget&quot;: &quot;contact&quot;, &quot;fields&quot;: [&quot;address&quot;, &quot;name&quot;, &quot;phone&quot;, &quot;fax&quot;], &quot;no_marker&quot;: true}"/>
                            </div>
                            <div t-if="o.picking_type_id.code != 'internal' and (not o.move_lines or not o.move_lines[0].partner_id) and o.picking_type_id.warehouse_id.partner_id">
                                <span><strong>Warehouse Address:</strong></span>
                                <div t-field="o.picking_type_id.warehouse_id.partner_id" t-field-options="{&quot;widget&quot;: &quot;contact&quot;, &quot;fields&quot;: [&quot;address&quot;, &quot;name&quot;, &quot;phone&quot;, &quot;fax&quot;], &quot;no_marker&quot;: true}"/>
                            </div>
                        </div>
                    </div>
                    <h2>
                    <span t-field="o.picking_type_id"/>:
                    <span t-field="o.name"/>
                    </h2>
                    <table class="table table-condensed">
                    <thead>
                        <tr>
                            <th><strong>Order (Origin)</strong></th>
                            <th><strong>State</strong></th>
                            <th><strong>Commitment Date</strong></th>
                            <th name="td_sched_date_h"><strong>Scheduled Date</strong></th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>
                                <span t-field="o.origin"/>
                            </td>
                            <td>
                                <span t-field="o.state"/>
                            </td>
                            <td>
                                <span t-field="o.date"/>
                            </td>
                            <td name="td_sched_date">
                                <span t-field="o.min_date"/>
                            </td>
                        </tr>
                    </tbody>
                    </table>
                    <br/>
                    <br/>
                    <table class="table table-condensed" t-if="not o.pack_operation_ids">
                      <thead>
                        <tr>
                            <th><strong>Product</strong></th>
                            <th class="text-center"><strong>Quantity</strong></th>
                            <t t-if="o.picking_type_id.code != 'incoming'">
                            <th><strong>Source</strong></th></t>
                            <th><strong>Barcode</strong></th>
                            <t t-if="o.picking_type_id.code != 'outgoing'"><th><strong class="text-center">Destination</strong></th></t>
                        </tr>
                      </thead>
                      <tbody>
                        <tr t-foreach="o.move_lines" t-as="move">
                            <td><span t-field="move.product_id"/></td>
                            <td class="text-right"><span t-field="move.product_uom_qty"/> <span t-field="move.product_uom" groups="product.group_uom"/></td>
                            <t t-if="o.picking_type_id.code != 'incoming'"><td><span t-field="move.location_id"/></td></t>
                            <td>
                                <span t-if="move.product_id and move.product_id.ean13">
                                    <img t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s' % ('EAN13', move.product_id.ean13, 600, 100)" style="width:300px;height:50px"/>
                                </span>
                            </td>
                            <t t-if="o.picking_type_id.code != 'outgoing'"><td><span t-field="move.location_dest_id"/></td></t>
                        </tr>
                      </tbody>
                    </table>
                    <table class="table table-condensed" t-if="o.pack_operation_ids">
                      <thead>
                        <tr>
                            <th><strong>Product</strong></th>

                            <th class="text-right"><strong>Quantity</strong></th>
                            <t t-if="o.picking_type_id.code != 'incoming'"><th><strong>Source</strong></th></t>
                            <th><strong>Barcode</strong></th>
                            <t t-if="o.picking_type_id.code != 'outgoing'"><th><strong>Destination</strong></th></t>
                        </tr>
                      </thead>
                      <tbody>
                        <tr t-foreach="o.pack_operation_ids" t-as="pack_operation">
                            <td><span t-field="pack_operation.product_id"/>
                                <t t-if="not pack_operation.product_id and pack_operation.package_id"><span t-field="pack_operation.package_id"/></t></td>

                            <td class="text-right"><span t-field="pack_operation.product_qty"/> <span t-field="pack_operation.product_uom_id" groups="product.group_uom"/></td>
                            <t t-if="o.picking_type_id.code != 'incoming'"><td><span t-field="pack_operation.location_id"/>
                                <span t-if="pack_operation.package_id">:</span>
                                <span t-field="pack_operation.package_id"/>
                                <span t-if="pack_operation.lot_id">:</span>
                                <span t-field="pack_operation.lot_id"/>
                                </td>
                            </t>
                            <td>
                                <span t-if="pack_operation.lot_id">
                                    <img t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s' % ('Code128', pack_operation.lot_id.name, 600, 100)" style="width:300px;height:50px"/>
                                </span>
                                <span t-if="pack_operation.product_id and not pack_operation.lot_id and pack_operation.product_id.ean13">
                                    <img t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s' % ('EAN13', pack_operation.product_id.ean13, 600, 100)" style="width:300px;height:50px"/>
                                </span>
                                <span t-if="pack_operation.package_id and not pack_operation.product_id">
                                    <img t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s' % ('Code128', pack_operation.package_id.name, 600, 100)" style="width:300px;height:50px"/>
                                </span>
                            </td>
                            <t t-if="o.picking_type_id.code != 'outgoing'"><td><span t-field="pack_operation.location_dest_id"/>
                                <span t-if="pack_operation.result_package_id">:</span>
                                <span t-field="pack_operation.result_package_id"/>
                            </td></t>
                        </tr>
                      </tbody>
                    </table>
                    <br/>
                    <br/>
                    <br/>
                    <br/>
                    <br/>
                    <br/>
                    <table border="0" style="border-collapse:collapse;color:000000;width:100%" cellpadding="3" cellspacing="3">
                        <tr>
                            <td  class="text-center" >________________________</td>
                            <td  class="text-center" >________________________</td>
                        </tr>
                        <tr >
                            <td class="text-center" >
                               <strong>Nombre y Firma Entrega</strong>
                            </td>
                            <td class="text-center" >
                               <strong>Nombre y Firma Recepcion</strong>
                            </td>
                            
                        </tr>
                    </table>

                </div>
            </xpath>
        </template>




Llamar funciones python desde Qweb Reports

Funciones Python desde Qweb Reports



    Qweb Reports el nuevo Reporteador para Odoo, ofrece muchas ventajas como lo ofrecía anteriormente RML, en ocaciones no podemos ejecutar directamente una operacion en Qweb o necesitamos tener un resultado de una funcion, esto es muy sencillo en RML, vamos a tomar como ejemplo las Facturas y voy a ejecutar un metodo desde el reporte Qweb, para calcular manualmente el total de un producto:


Qweb


<span  t-esc="line.subtotal_manual(line.price_unit,line.quantity)"/>

    Como podemos observar line es mi variable de iteracion para obtener los valores de invoice_lines, las lineas de Factura, para ejecutar un metodo llamado subtotal_manual. Este metodo que estamos utilizando no existe en el objecto account.invoice.line, así que tendremos que crearlo.

Clases Python

# -*- encoding: utf-8 -*-
############################################################################
#    (c) 2015 German Ponce Dominguez
#    All Rights Reserved.
#    info skype: german_442 email: (german.ponce@outlook.com)
############################################################################

from openerp.osv import fields, osv
from openerp.tools.translate import _
from datetime import datetime, timedelta
from openerp import SUPERUSER_ID

class account_invoice_line(osv.osv):
    _name = 'account.invoice.line'
    _inherit ='account.invoice.line'
    _columns = {

        }

    _defaults = {
        }

    def subtotal_manual(self, price, qty):
        return price*qty

    En la clase python account_invoice_line, se añade el metodo que queremos ejecutar, esto sera variable de acuerdo al objecto en donde quieran ejecutar su funcion.