Como crear informes RML desde OpenOffice para OpenERP

En OpenERP hay muchas alternativas a la hora de hacer informes, personalmente me gusta mucho Jasper, porque visualmente puedes hacer lo que quieras, pero el motor por defecto de OpenERP es OpenReports, este motor permite imprimir informes a partir de ficheros RML. Un fichero RML es un fichero XML que define unos datos y una estructura para que el motor de OpenReport pueda transformarlo en un informe HTML o PDF. El RML que se transforma en HTML o en PDF tiene los datos en bruto, es decir si quiero imprimir un listado de clientes, el RML tiene ese listado que voy a imprimir, pero puedo crear un RML con etiquetas y el motor de OpenERP se encargará de sustituirlas por los datos referenciados. Pero… ¿Como puedo crear ese informe RML? Hacer un XML e intentar que salga como queremos visualmente es muy pesado, vamos a ver como hacer un informe en OpenOffice, transformarlo en RML con SXW2RML y añadirlo a nuestro módulo.


La información de este manual la he sacado del capítulo OpenOffice.org Reports del developer book, puedes consultarlo si algo no queda claro o para ampliar información.

Para añadir un informe en nuestro módulo tenemos que crear una carpeta reports y dentro crearemos el fichero.rml que es el propio informe , otro fichero con la clase python para imprimir el informe, el __init__.py, un fichero xml para la vista, define donde lo vamos a imprimir, y añadiremos la ruta del xml al fichero __openerp__.py del modulo y el import report al __init__.py.

Preparando el informe en OpenOffice

Vamos por partes, lo primero es obtener el informe.rml, vamos ha obtenerlo a partir de un documento de OpenOffice. Vamos a crear en OpenOffice un documento con los la estructura que queramos para nuestro informe, para que OpenERP complete nuestro informe con datos dinamicos tendremos que indicar los objetos que queremos mostrar con etiquetas escritas entre corchetes.

Lo normal es lanzar el informe asociándolo a un objeto desde la vista del grid seleccionando varias instancias o desde la vista para una única instancia del objeto. Para hacer esto tendremos que indicar en nuestro informa que vamos a imprimir los campos repitiendo sobre un objeto.

[[repeatIn(objects,'o')]

donde “objects” es el parámetro del que obtenemos el objeto a imprimir de OpenERP y “o” es el nombre que le hemos dado para referenciarlo en el informe.

después de esta instrucción podremos imprimir cualquier campo del objeto sobre el que lancemos el objeto de la siguiente forma

[[o.campo]]

donde “campo” es un campo simple del objeto “o” pasado para ejecutar el informe.

Si uno de los campos del objeto es otro objeto y la relación es one2many podemos imprimir los campos así:

[[o.campo_one2many.campo1]]
[[o.campo_one2many.campo2]]

donde “campo1” y “campo2” son campos del objeto asociado en el campo “campo_one2many” del objeto “o”.

Para los campos del tipo many2many o many2one, tendremos que iterar, porque el objeto que estamos imprimiendo puede tener varios objetos asociados, esto lo podemos hacer así:

[[repeatIn(o.many_ids,'many_etiq')]]
[[many_etiq.campo1]]
[[many_etiq.campo2]]

donde “many_ids” es un campo del tipo many2many o many2one del objeto “o”, “many_etiq” es el nombre que le hemos dado para referenciarlo y “campo1” y “campo2” son campos del objeto relacionado en el campo “many_ids”.

Una vez tienes has creado el documento, para poder convertirlo en rml hay que guardarlo con la extensión .swx.
Para ver un ejemplo puedes mirar en el modulo sale, el informe sale-order.sxw en addons/sale/report, y para verlo impreso ve al formulario de pedidos de venta y dale a imprimir.

De OpenOffice a RML

Ahora vamos a ver como transformar este documento .sxw a uno .rml. Para hacerlo vamos ha utilizar sxw2rml, si miras en la documentación, a dia de hoy está indicado para la versión 5, ha cambiado un poco para la versión 6 de OpenERP.

En la versión 5 el ejecutable erá tiny_swx2rml.py y se podía encontrar en:
server/bin/addons/base_report_designer/wizard/tiny_sxw2rml/tiny_sxw2rml.py

Para la versión 6 se llama openerp_sxw2rml.py y se encuentra en:
server/bin/addons/base_report_designer/wizard/openerp_sxw2rml/openerp_sxw2rml.py

Suponiendo que queremos añadir el informe en un módulo que estamos desarrollando al que llamamos “mi_modulo” y tenemos su carpeta en el directorio addons del servidor y nuestro documento de openoffice lo llamamos “mi_informe.sxw” y lo tenemos en la carpeta “reports” de nuestro informe, para convertir nuestro informe a rml trabajando con la versión 6 podemos hacer lo siguiente:
cd server/bin/addons/base_report_designer/wizard/openerp_sxw2rml/
python ./openerp_sxw2rml.py ../../mi_modulo/report/mi_informe.sxw > ../../mi_modulo/report/mi_informe.rml

Añadiendo el informe al módulo

Hasta aquí ya tenemos nuestro informe rml, vamos a ver como imprimirlo desde OpenERP. Lo primero que necesitamos es crear el directorio report en nuestro módulo, dentro de este directorio incluiremos el informe rml, opcionalmente el swx para poder modificarlo luego. Necesitaremos también dentro de este directorio un fichero .py que será la clase que generará el report y el __init__.py con el import del fichero anterior. Para incluir el enlace en una ventana determinada tendrémos que crear un xml, en el que indicaremos desde donde lo imprimimos. Por último tendremos que incluir el una línea con “import report” dentro del __init__.py del módulo y incluir el xml en el __openerp__.py. Podemos ver estos archivos tomando como ejemplo el pedido de venta ( sale order), que esta en el módulo sale.

Si miramos el contenido de sale_order.py


import time

from report import report_sxw

class order(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context=None):
super(order, self).__init__(cr, uid, name, context=context)
self.localcontext.update({
‘time’: time,
})

report_sxw.report_sxw(‘report.sale.order’, ‘sale.order’, ‘addons/sale/report/sale_order.rml’, parser=order, header=”external”)

La clase order es el parser, que hereda de report_sxw.rml_parse, y genera el informe, reemplazando las etiquetas por los datos del objeto. En la llamada a report_sxw.report_sxw(…) le pasamos esta clase como parser. El primer parámetro es el nombre del propio informe, el segundo sobre que clase se van a sacar los datos, el tercero es la ruta del fichero rml, y el último indica si queremos imprimir la cabecera, si ponemos “true” imprimirá la cabecera configurada en OpenERP.

Vamos a ver el xml de la vista que indica que se puede imprimir este informe desde la ventana de pedidos de venta, el fichero es sale_report.xml

Por último para añadir estos fichero al módulo tendremos que añadir en el __init__.py del módulo:
import report

en el en el __init__.py del directorio report:
import sale_order

Y en el __openerp__.py, tenemos que añadir el sale_report.xml para que lo cargue con el módulo.
'update_xml': [... ,'sale_report.xml', ]

Y con esto ya tenemos el informe metido en el módulo, si quieres probarlo recuerda que tendrás que reiniciar el servidor con la opción -u y el nombre del módulo para recargarlo.

17 comentarios sobre “Como crear informes RML desde OpenOffice para OpenERP

  1. Maybe

    Hola, estuve leyendo tu articulo y esta muy bueno, pero tengo duda con el campo one2many. Asi como lo dices me lanza en el reporte en vez de la lista de objetos: browse_record_list(2) haciendo referencia q hay dos objetos dentro de ese one2many. Lo que quiero es q me muestre campos q pertenecen a los objetos de esa lista y de la cual no se a priori la cantidad de elemento, sino me pararia en una posicion x.

    Como podria iterar este campo one2many?
    Saludos

  2. Juan Jimbo

    buenas amigo esta bueno tu aporte queria preguntar como se pueden hacer reportes con graficos para openerp

    algo como una grafica de crecimiento

  3. Stiven

    hola pero como se puede hacer para realizar una suma de los campos total de todos los registros y que aparesca en la inferior del informe. en jasper se hace con un sumary pero en openoffice no lo puedo solucionar.

  4. anonimo

    Hola, mira estoy modificando el reporte Sale with Layaout, el caso es que utiliza el objeto sale.order.line, para crear presupuestos desde Pedido de Venta. Me gustaría que apareciera la categoria a la que pertenece el producto que voy a presupuestar.
    Lo he intentado de mil maneras, se que el objeto sale.order.line tiene un campo llamado product_id, many2one, que tiene relacion con el objeto product.product, por lo que he entendido.
    Muchas gracias de ante mano.

  5. Angel Moya Autor del artículo

    Creo que la mejor solución es crear ese campo como un campo calculado en orm y luego mostrarlo en el informe. Si tienes dudas mira como se calcula el importe total en los pedidos de venta.

  6. Angel Moya Autor del artículo

    Has probado product_id.categ_id o product_id.product_tmpl_id.categ_id.

  7. anonimo

    Muchas gracias! puse product_id.product_tmpl_id.categ_id y funciono. Pero ahora te voy hacer otra consulta.
    A la hora de añadir loop te aparece una cosa como esta [[ repeatIn(objects,’o’) ]], en objects se pone el objeto sobre el que queremos iterar no?, y la o es una etiqueta que nosotros le ponemos.
    Lo que me pasa es que en el mismo documento, si pongo un repeat y luego otro repeat con otro objeto me deja de funcionar el anterior.
    Y por último es normal que cada vez que tenga que añadir un field, tenga que añadir un loop?, es que si no lo hago asi, no me aparece nada en la lista de campos cuando doy a add field.
    Es que la verdad encuentro muy poca informacion sobre esta sintaxis.

    Muchas gracias

  8. anonimo

    Buenos días,
    Ha esto me refiero con el comentario anterior a lo referente a los bucles.
    Tengo la siguiente situación:
    (primera tabla)
    COD ÁREA/ACTIVIDAD TRABAJO (a continuacion pongo)
    [[repeatIn(o.order_line,’line’)]]
    (segunda tabla)
    [[ line.product_id.product_tmpl_id.categ_id.name ]] [[line.name]]

    Esto me lo muestra bien,ahora pongo:

    Descripcion trabajo (en una linea normal)
    …………………………….
    [[line.notes]](tercera tabla)

    Y ya no me lo muestra, como que el bucle anterior no lo pilla o algo,he puesto un bucle como el de antes,[[repeatIn(o.order_line,’line’)]],justo antes de la tercera tabla y me dice que el objeto ‘o’ no esta definido.

    Muchísimas Gracias.

  9. Angel Moya Autor del artículo

    Si te funciona [[line.name]] y luego no muestra [[line.note]] tiene que haber algo mal,¿por que no lo pones en la misma tabla?

  10. daniel

    hola, interesante articulo, yo estoy tratando de imprimir un campo many2one

    PATRON: [[ repeatIn(picking.x_no_patron, ‘x_no_patron’)]] [[x_no_patron.name]]

    pero no me funciona, alguna sugerencia.
    picking es el objeto, el campo es x_no_patron y quiero que me aparezca el nombre

  11. ifrain.alejandro

    Hola a todos!!!
    Soy nuevo trabajando con OpenERP y estoy tratando de crear infomes para un modulo que acabo de realizar. Existe actualmente alguna otra herramienta para diseñar reportes para OpenERP que no sea precisamente con el OpenOffice?

  12. Angel Moya Autor del artículo

    Buenas, realmente lo mejor es editar directamente el rml, que no es mas que un rml, pero también está la opción de instalar el módulo que integra reportes jasper, para poder crearlos con iReport.

  13. José Miguel

    Buenas tardes,
    Me gustaría saber si es posible reducir el tamaño de un gráfico de pastel en openerp y de ser posible agradecería una pista de como hacerlo.

  14. Over Garcia

    Muchas gracias por todo el aporte en este blog porque cuando se empieza con los reportes de OpenERP, son muchas las dudas y poca la documentación.
    Depronto alguno de Uds. me puede ayudar con el siquiente inconveniente.
    Tengo que crear una factura que agrupe los productos por categoría y hacer un subtotal por cada categoría. Creé un objeto que sume por categoría asociada a la factura. En el reporte rml recorró el nuevo objeto sin error, pero cómo se recorre el segundo ciclo filtrando solo los productos que pertenecen a la categoría vigente del primer ciclo?. Intente realizar lo siguiente pero no funcionó.

    Primer ciclo:
    repeatIn(o.total_categ_id,’cat’)

    segundo ciclo:
    repeatIn(filter(lambda l: ‘cat.categ_id.name’ in l.product_id.categ_id.complete_name,o.invoice_line), ‘li’)

    Si reemplazo cat.categ_id.name en el sugundo ciclo por el nombre de la categoria (ej. “TURBO”), si funciona, pero no filtra.

    Mil gracias por cualquier sugerencia

  15. Lourdes

    Soy nueva en OpenERP y quisiera saber como puedo lograr que al imprimir un reporte no me muestre eol documento, es decir vaya directamente para la impresora. Graciassss

  16. Benjamin Acevedo

    Hola y primero que todo muchas gracias por el aporte,, realmente ayuda mucho.. tengo un problema estoy modificando el layout de sales order , y pude imprimir el campo child_ids pero sale con fallos, podrias poner un ejemplo de como imprimir un campo de tipo one2many,,
    este es mi parametro saludos
    [[(o.partner_id.child_ids.name,’line’) ]]

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *