Вы находитесь на странице: 1из 15

Construyendotuprimeraaplicacincon

Odoo
DesarrollarenOdoolamayoradelasvecessignificacrearnuestrospropiosmdulos.Enestecaptulo,se
crearlaprimeraaplicacinconOdoo,yseaprendernlospasosnecesariosparahabilitarlaseinstalarlasen
Odoo.
Inspiradosdelnotableproyectotodomvc.com,sedesarrollarunasimpleaplicacinparaelregistrodecosas
porhacer.Deberpermitiragregarnuevastareas,marcarlascomoculminadas,yfinalmenteborrardelalista
todaslastareasfinalizadas.
AprendercomoOdoosigueunaarquitecturaMVC,yrecorrerlassiguientescapasdurantela
implementacindelaaplicacin:Elmodelo,definelaestructuradelosdatos.Lavista,describelainterfaz
conelusuarioolausuaria.Elcontrolador,soportalalgicadenegociodelaaplicacin.
LacapamodeloesdefinidaporobjetosPythoncuyosdatossonalmacenadosenunabasededatos
PostgreSQL.ElmapeodelabasededatosesgestionadoautomticamenteporOdoo,yelmecanismo
responsableporestoeselmodeloobjetorelacional,(ORMobjectrelationalmodel).
Lacapavistadescribelainterfazconelusuarioolausuaria.LasvistassondefinidasusandoXML,lascuales
sonusadasporelmarcodetrabajo(framework)delclientewebparagenerarvistasHTMLdedatos.
Lasvistasdelclientewebejecutanaccionesdedatospersistentesatravsdelainteraccinconelservidor
ORM.Estaspuedenseroperacionesbsicascomoescribiroeliminar,peropuedentambininvocarmtodos
definidosenlosobjetosPythondelORM,ejecutandolgicadenegociomscompleja.Aestoesaloquenos
referimoscuandosehabladelacapamodelo.

Nota
Notequeelconceptodecontroladormencionadoaquesdiferentealdesarrollode
controladoreswebdeOdoo.Aquellossonprogramasfinalesaloscualeslaspginasweb
puedenllamarparaejecutaracciones.

Conesteenfoque,podrsercapazdeaprendergradualmentesobrelosbloquesbsicosdedesarrolloque
conformanunaaplicacinyexperimentarelprocesoiterativodeldesarrollodemdulosenOdoodesdecero.

Entenderlasaplicacionesylosmdulos
EscomnescucharhablarsobrelosmdulosylasaplicacionesenOdoo.Pero,Cualesexactamentela
diferenciaentreunmduloyunaaplicacin?Losmdulossonbloquesparalaconstruccindelas
aplicacionesenOdoo.UnmdulopuedeagregaromodificarcaractersticasenOdoo.Estoessoportadopor
undirectorioquecontieneunarchivodemanifiestoodescriptor(llamado __openerp__.py )yelrestodelos
archivosqueimplementansuscaractersticas.Aveces,losmdulospuedenserllamados"addons"
(complementos).Lasaplicacionesnosondiferentesdelosmdulosregulares,perofuncionalmente,stas
proporcionanunacaractersticacentral,alrededordelacualotrosmdulosagregancaractersticasu

opciones.Estasproveenloselementosbaseparaunreafuncional,comocontabilidadoRRHH,sobrelas
cualesotrosmdulosagregancaractersticas.PorestosonresaltadasenelmenAppsdeOdoo.

Modificarunmduloexistente
Enelejemploquesigueacontinuacin,crearemosunmdulonuevocontanpocasdependenciascomosea
posible.
Sinembargo,estenoeselcasotpico.Lomsfrecuentesernsituacionesdondelasmodificacionesy
extensionessonnecesariasenunmduloexistenteparaajustarloacasosdeusoespecficos.
Laregladeorodicequenodebemoscambiarmdulosexistentesmodificndolosdirectamente.Estoes
consideradounamalaprctica.EspecialmenteciertoparalosmdulosoficialesproporcionadosporOdoo.
Hacerestonopermitirunaclaraseparacinentreelmdulooriginalynuestrasmodificaciones,yhacedifcil
laactualizacin.
Porelcontrario,debemoscrearmdulosnuevosqueseanaplicadosencimadelosmdulosquequeremos
modificar,eimplementaresoscambios.EstaesunadelasprincipalesfortalezasdeOdoo:provee
mecanismosde"herencia"quepermitenalosmdulospersonalizadosextenderlosmdulosexistentes,bien
seanoficialesodelacomunidad.Laherenciaelposibleentodoslosniveles,modelodedatos,lgicade
negocio,einterfazconelusuarioousuaria.
Ahora,crearemosunmdulonuevocompleto,sinextenderningnmduloexistente,paraenfocarnosenlas
diferentespartesypasosinvolucradosenlacreacindeunmdulo.Solodaremosunabrevemiradaacada
parte,yaquecadaunaserestudiadaendetalleenlossiguientescaptulos.Unavezestemosagustoconla
creacindeunmdulonuevo,podremossumergirnosdentrodelosmecanismosdeherencia,loscuales
sernestudiadosenelsiguientecaptulo.

Crearunmdulonuevo
Nuestromduloserunaaplicacinmuysimpleparagestionarlastareasporhacer.Estastareastendrnun
nicocampodetexto,paraladescripcin,yunacasilladeverificacinparamarcarlascomoculminadas.
Tambintendremosunbotnparalimpiarlalistadetareasdetodasaquellasfinalizadas.
Estasespecificacionessonmuysimples,peroamedidaqueavancemosenellibroiremosagregando
gradualmentenuevascaractersticas,parahacerlaaplicacinmsinteresante.
Bastadecharla,comencemosaescribircdigoycrearnuestronuevomdulo.
SiguiendolasinstruccionesdelCaptulo1,ComenzandoconOdoo,debemostenerelservidorOdoo
en /odoodev/odoo/ .Paramantenerlascosasordenadas,crearemosundirectoriojuntoaesteparaguardar
nuestrospropiosmdulos:

$mkdir~/odoodev/customaddons
UnmduloenOdooesundirectorioquecontieneunarchivodescriptor __openerp__.py .Estoesunaherencia
decuandoOdoosellamabaOpenERP,yenelfuturoseesperaseconviertaen __odoo__.py .Esnecesario
quepuedaserimportadodesdePython,porloquedebetenerunarchivo __init__.py .
Elnombredeldirectoriodelmdulosersunombretcnico.Usaremos todo_app paraelnombre.Elnombre
tcnicodebeserunidentificadorPythonvalido:debecomenzarconunaletraypuedecontenerletras,
nmerosyelcarcterespecialguinbajo.Lossiguientescomandoscreaneldirectoriodelmduloyelarchivo
vaco __init__.py dentrodeeste:

$mkdir~/odoodev/customaddons/todo_app
$touch~/odoodev/customaddons/todo_app/__init__.py
Luegonecesitamoscrearelarchivodescriptor.DebecontenernicamenteundiccionarioPythonypuede
conteneralrededordeunadocenadeatributos,deloscualessoloelatributo name esobligatorio.Son
recomendadoslosatributos description ,paraunadescripcinmslarga,y author .Ahoraagregamosun
archivo __openerp__.py juntoalarchivo __init__.py conelsiguientecontenido:

{
'name':'ToDoApplication',
'description':'ManageyourpersonalTaskswiththismodule.',
'author':'DanielReis',
'depends':['mail'],
'application':True,
}
Elatributo depends puedetenerunalistadeotrosmdulosrequeridos.Odoolosinstalarautomticamente
cuandoestemduloseainstalado.Noesunatributoobligatorioperoserecomiendatenerlosiempre.Sinoes
requeridaalgunadependenciaenparticular,deberaexistiralgunadependenciaaunmdulobaseespecial.
Debetenercuidadodeasegurarsequetodaslasdependenciasseanexplcitamentefijadasaqu,deotra
formaelmdulopodrafallaralinstalarunabasededatosvaca(debidoadependenciasinsatisfechas)o
tenererroresenlacarga,siotrosmdulosnecesariossoncargadosdespus.
Paranuestraaplicacin,queremosquedependadelmdulomaildebidoaqueesteagregael
menMensajeraenlapartesuperiordelaventana,yqueremosincluirnuestronuevomendeopcionesall.
Paraprecisar,escogimospocasclavesdeldescriptor,peroenelmundorealesrecomendableusarclaves
adicionales,yaqueestassonrelevantesparalaappstoredeOdoo:
summary ,muestraunsubtitulodelmdulo.
version ,deformapredeterminada,es1.0.Sedebeseguirlasreglasdeversionamientosemntico(para
msdetallesversemver.org).
license ,deformapredeterminadaesAGPL3.
website ,esunaURLparaencontrarmsinformacinsobreelmdulo.Estapuedeserviralaspersonas
aencontrardocumentacin,informarsobreerroresohacersugerencias.
category ,eslacategorafuncionaldelmdulo,lacualdeformapredeterminadaesSinCategora.Lalista
delascategorasexistentespuedeencontrarseenelformatodeGrupos(Configuraciones|Usuarios|
menGrupos),enlalistadesplegabledelcampoAplicacin.

Estosdescriptorestambinestndisponibles: installable ,deformapredeterminadaes True ,peropuede


serfijada False paradeshabilitarelmdulo. auto_install ,siestafijadaen True estemduloes
automticamenteinstaladositodaslasdependenciashansidoinstaladas.Estoesusadoenmdulos
asociados.
DesdeOdoo8.0,envezdelaclave description podemosusarunarchivo README.rst o README.md enel
directoriorazdelmdulo.

Agregarelmduloalarutadecomplementos
Ahoraquetenemosunmdulonuevo,inclusosiesmuysimple,queremosqueestdisponibleenOdoo.Para
esto,debemosasegurarnosqueeldirectorioquecontieneelmduloseapartedelarutadecomplementos
addons.YluegotenemosqueactualizarlalistademdulosdeOdoo.

Ambasoperacioneshansidoexplicadasendetalleenelcaptuloanterior,peroacontinuacinpresentamos
unresumendelonecesario.
Nosposicionamosdentrodeldirectoriodetrabajoeiniciamoselservidorconlaconfiguracindelarutade
complementosoaddons:

$cd~/odoodev
$odoo/odoo.pydv8devaddonspath="customaddons,odoo/addons"save
Laopcin save guardalaconfiguracinusadaenunarchivodeconfiguracin.Estoevitarepetirlocadavez
queelservidoresiniciado:simplementeejecute./odoo.pyysernejecutadaslasltimasopcionesguardadas.
Miradetenidamenteenelregistrodelservidor.DeberahaberunalneaINFO?openerp:addons
paths:(...),ydeberaincluirnuestrodirectorio customaddons .
Recuerdeincluircualquierotrodirectorioquepuedaestarusando.Porejemplo,sisiguilasinstruccionesdel
ltimocaptuloparainstalarelrepositoriodepartment,puedequererincluirloyusarlaopcin:

addonspath="customaddons,department,odoo/addons"
AhorahagamosqueOdoosepadelosmdulosnuevosquehemosincluido.
Paraesto,EnlaseccinMdulosdelmenConfiguracin,seleccionelaopcinActualizarlistade
mdulos.Estoactualizarlalistademdulosagregandocualquiermduloincluidodesdelaltima
actualizacindelalista.RecuerdequenecesitamoshabilitarlasCaractersticasTcnicasparaqueesta
opcinseavisible.EstoselograseleccionandolacajadeverificacindeCaractersticastcnicaspara
nuestracuentadeusuario.

Instalarelmdulonuevo
LaopcinMduloslocalesnosmuestralalistademdulosdisponibles.Deformapredeterminadasolo
muestralosmdulosdeAplicacionesenlnea.Debidoaquecreamosunmdulodeaplicacinnoes
necesarioremoverestefiltro.Escriba"todo"enlacampodebsquedaydebevernuestromdulonuevo,listo
paraserinstalado.

Grfico2.1Instalarnuevomdulo'todo_app'
HagaclicenelbotnInstalarylisto!

Actualizarunmdulo
Eldesarrollodeunmduloesunprocesoiterativo,ypuedequererqueloscambioshechosenlosarchivos
fuenteseanaplicadosyestnvisiblesenOdoo.

Enlamayoradeloscasosestoeshechoatravsdelaactualizacindelmdulo:busqueelmduloenlalista
deMdulosLocalesy,yaqueestinstalado,debepoderverelbotnActualizar.
Decualquierforma,cuandoloscambiosrealizadossonenelcdigoPython,laactualizacinpuedenotener
ningnefecto.Enestecasoesnecesarioreiniciarlaaplicacinenelservidor.
Enalgunoscasos,sielmdulohasidomodificadotantoenlosarchivosdedatoscomoenelcdigoPython,
puedensernecesariasambasoperaciones.Esteesunpuntocomndeconfusinparalaspersonasquese
inicianeneldesarrolloconOdoo.
Peroafortunadamente,existeunamejorforma.Laformamssimpleyrpidaparahacerefectivostodoslos
cambiosennuestromduloesdetener(Ctrl+C)yreiniciarelprocesodelservidorquerequierequenuestros
mdulosseanactualizadosenlabasededatosdetrabajo.
Parahacerqueelservidorinicielaactualizacindelmdulo todo_app enlabasededatosv8dev,usaremos:

$./odoo.pydv8devutodo_app
Laopcin u (o update ensuformalarga)requierelaopcin d yaceptaunalistaseparadaporcomas
demdulosparaactualizar.Porejemplo,podemosusar: utodo_app,mail .
Enelmomentoenquenecesiteactualizarunmduloenprocesodedesarrolloalolargodellibro,lamanera
masseguradehacerloesiraunaventanadeterminaldondeseesteejecutandoOdoo,detenerelservidor,y
reiniciarloconelcomandovistoanteriormente.Usualmentesersuficienteconpresionarlatecladeflecha
arriba,estodeberadevolverelltimocomandousadoparainiciarelservidor.
Desafortunadamente,laactualizacindelalistademdulosyladesinstalacinsonaccionesquenoestn
disponiblesatravsdelalneadecomandos.Estodebeserrealizadoatravsdelainterfazweb,enelmen
Configuraciones.

Crearunmodelodeaplicacin
AhoraqueOdoosabesobreladisponibilidaddenuestromdulonuevo,comencemosaagregarleunmodelo
simple.
Losmodelosdescribenlosobjetosdenegocio,comounaoportunidad,unaordendeventa,ounsocio
(cliente,proveedor,etc).Unmodelotieneunalistadeatributosytambinpuededefinirsunegocioespecfico.
LosmodelossonimplementadosusandoclasesPythonderivadasdeunaplantilladeclasedeOdoo.Estos
sontraducidosdirectamenteaobjetosdebasededatos,yOdooseencargadeestoautomticamentecuando
elmduloesinstaladooactualizado.
AlgunaspersonasconsiderancomobuenaprcticamantenerlosarchivosPythonparalosmodelosdentrode
unsubdirectorio.Porsimplicidadnoseguiremosestasugerencia,asquevamosacrearun
archivo todo_model.py eneldirectoriorazdelmdulo todo_app .
Agregarelsiguientecontenido:

#*coding:utf8*
fromopenerpimportmodels,fields

classTodoTask(models.Model):
_name='todo.task'
name=fields.Char('Description',required=True)

is_done=fields.Boolean('Done?')
active=fields.Boolean('Active?',default=True)
LaprimeralneaesunmarcadorespecialqueledicealinterpretedePythonqueesearchivoesUTF8,porlo
quepuedemanejaryesperarsecaracteresnonASCII.Nousaremosninguno,peroesmassegurousarlo.
LasegundalneahacequeestndisponibleslosmodelosylosobjetoscamposdelncleodeOdoo.
laterceralneadeclaranuestronuevomodelo.Esunaclasederivadade models.Model .Lasiguientelneafija
elatributo _name definiendoelidentificadorqueserusadoporOdooparareferirseaestemodelo.Noteque
elnombrerealdelaclasePythonnoessignificativoparalosotrosmdulosdeOdoo.Elvalorde _name eslo
queserusadocomoidentificador.
Observequestasylassiguienteslneastienenunasangra.SinoconocemuybienPythondebesaberque
estoessumamenteimportante:lasangradefineunbloquedecdigoanidado,porlotantoestascuatro
lneasdebentenerlamismasangra.
Lasltimastreslneasdefinenloscamposdelmodelo.Valelapenasealarque name y active sonnombres
decamposespeciales.DeformapredeterminadaOdoousaraelcampo name comoelttulodelregistro
cuandoseareferenciadodesdeotrosmodelos.Elcampo active esusadoparadesactivarregistros,yde
formapredeterminadasololosregistrosactivossonmostrados.Lousaremosparaquitarlastareasfinalizadas
sineliminarlasdefinitivamentedelabasededatos.
Todava,estearchivo,noesusadoporelmdulo.DebemosdecirleaOdooquelocargueconelmduloenel
archivo __init__.py .Editemoselarchivoparaagregarlasiguientelnea:

from.importtodo_model
Estoestodo.paraquenuestroscambiostenganefectoelmdulodebeseractualizado.Encuentrela
aplicacinToDoenMdulosLocalesyhagaclicenelbotnActualizar.
AhorapodemosrevisarelmodelorecincreadoenelmenTcnico.VayaaEstructuradelaBasede
Datos|Modelosybusqueelmodelo todo.task enlalista.Luegohagaclicenesteparaversudefinicin:

Grfico2.2VistadeEstructuradelaBasedeDatosdemdulo'todo_app'

Sinohuboningnproblema,estonosconfirmarqueelmodeloynuestroscamposfueroncreados.Sihizo
algunoscambiosynosonreflejados,intentereiniciarelservidor,comofuedescritoanteriormente,para
obligarquetodoelcdigoPythonseacargadonuevamente.
Tambinpodemosveralgunoscamposadicionalesquenodeclaramos.Estossoncincocamposreservados
queOdooagregaautomticamenteacualquiermodelo.Sonlossiguientes: id :Esteeselidentificador
nicoparacadaregistroenunmodeloenparticular. create_date y create_uid :Estosnosindicancuando
elregistrofuecreadoyquienlocre,respectivamente. write_date y write_uid :Estosnosindicancuando
fuelaltimavezqueelregistrofuemodificadoyquienlomodific,respectivamente.

Agregarentradasalmen
Ahoraquetenemosunmodeloenelcualalmacenarnuestrosdatos,hagamosqueestedisponibleenla
interfazconelusuarioylausuaria.
Todoloquenecesitamoshaceresagregarunaopcindemenparaabrirelmodelode"TodoTask"para
quepuedaserusado.EstoesrealizadousandounarchivoXML.Igualqueenelcasodelosmodelos,algunas
personasconsiderancomounabuenapracticamantenerlasdefinicionesdevistasenenunsubdirectorio
separado.
Crearemosunarchivonuevo todo_view.xml eneldirectoriorazdelmdulo,yestetendrladeclaracinde
untemdemenylaaccinejecutadaporeste:

<?xmlversion="1.0"encoding="UTF8"?>
<openerp>
<data>
<!ActiontoopenTodoTasklist>
<act_window
id="action_todo_task"
name="TodoTask"
res_model="todo.task"
view_mode="tree,form"
/>
<!MenuitemtoopenTodoTasklist>
<menuitem
id="menu_todo_task"
name="ToDoTasks"
parent="mail.mail_feeds"
sequence="20"
action="action_todo_task"
/>
</data>
</openerp>
Lainterfazconelusuarioyusuaria,incluidaslasopcionesdelmenylasacciones,sonalmacenadasen
tablasdelabasededatos.ElarchivoXMLesunarchivodedatosusadoparacargaresasdefinicionesdentro
delabasededatoscuandoelmduloesinstaladooactualizado.EstoesunarchivodedatosdeOdoo,que
describedosregistrosparaseragregadosaOdoo:Elelemento <act_window> defineunaAccindeVentana
delladodelclienteparaabrirelmodelo todo.task definidoenelarchivoPython,conlasvistasderboly
formulariohabilitadas,eneseorden.Elelemento <menuitem> defineuntemdemenbajoelmen
Mensajera(identificadopor mail.mail_feeds ),llamandoalaaccin action_todo_task ,quefuedefinida
anteriormente.elatributo sequence nosdejafijarelordendelasopcionesdelmen.

AhoranecesitamosdecirlealmduloqueuseelnuevoarchivodedatosXML.Estoeshechoenel
archivo __openerp__.py usandoelatributo data .Estedefinelalistadearchivosquesoncargadosporel
mdulo.Agregueesteatributoaldiccionariodeldescriptor:

'data':['todo_view.xml'],
Ahoranecesitamosactualizarnuevamenteelmduloparaqueestoscambiostenganefecto.Vayaalmen
Mensajeraydebepodervernuestronuevaopcindisponible.

Grfico2.3Agregarmdulo'todo_app'almendeOdoo
Sihaceclicenellaseabrirunformulariogeneradoautomticamenteparanuestromodelo,permitiendo
agregarymodificarlosregistros.
Lasvistasdebenserdefinidasporlosmodelosparaserexpuestasalosusuariosylasusuarias,aunqueOdoo
eslosuficientementeamableparahacerloautomticamentesinoqueremos,entoncespodemostrabajarcon
nuestromodelo,sintenerningnformularioovistasdefinidasan.
Hastaahoravamosbien.Mejoremosahoranuestrainterfazgrfica.Intentelasmejorasgradualesqueson
mostradasenlasseccionessiguientes,haciendoactualizacionesfrecuentesdelmdulo,ynotengamiedode
experimentar.

Truco
EncasoqueunaactualizacinfalledebidoaunerrorenelXML,noentreenpnico!
ComentelasltimasporcionesdeXMLeditadas,oelimineelarchivoXML
del __openerp__.py ,yrepitalaactualizacin.Elservidordeberainiciarcorrectamente.
Luegoleadetenidamenteelmensajedeerrorenlosregistrosdelservidordebera
decirledondeestelproblema.

Crearvistasformulario,rbolybsqueda
Comohemosvisto,siningunavistaesdefinida,Odooautomticamentegenerarvistasbsicasparaque
puedascontinuar.Peroseguramentelegustardefinirsuspropiasvistasdelmdulo,asqueesoesloque
haremos.
Odoosoportavariostiposdevistas,perolastresprincipalesson: list (lista,tambinllamada
rbol), form (formulario),y search (bsqueda).Agregaremosunejemplodecadaunaanuestromdulo.
Todaslasvistassonalmacenadasenlabasededatos,enelmodelo ir.model.view .Paraagregarunavista
enunmdulo,declaramosunelemento <record> describiendolavistaenunarchivoXMLquesercargado
dentrodelabasededatoscuandoelmodeloseainstalado.

Creandounavistaformulario
EditeelXMLquerecinhemoscreadoparaagregarelelemento <record> despusdelaaperturadela
etiqueta <data> :

<recordid="view_form_todo_task"model="ir.ui.view">
<fieldname="name">TodoTaskForm</field>
<fieldname="model">todo.task</field>
<fieldname="arch"type="xml">
<formstring="TodoTask">
<fieldname="name"/>
<fieldname="is_done"/>
<fieldname="active"readonly="1"/>
</form>
</field>
</record>
Estoagregarunregistroalmodelo ir.ui.view conelidentificador view_form_todo_task .Paraelmodelola
vistaes todo.task ynombrada TodoTaskForm .Elnombreessoloparainformacin,notienequeser
nico,perodebepermitiridentificarfcilmenteaqueregistroserefiere.
Elatributomsimportantees arch ,quecontieneladefinicindelavista.Aqudecimosqueesunformulario,
yquecontienetrescampos,yquedecidimoshaceralcampo active desololectura.
Formatearcomoundocumentodenegocio
Loanteriorproporcionaunavistadeformulariobsica,peropodemoshaceralgunoscambiosparamejorarsu
apariencia.ParalosmodelosdedocumentosOdootieneunestilodepresentacinqueasemejaunahojade
papel.Elformulariocontienedoselementos:una <head> ,quecontienebotonesdeaccin,yun <sheet> ,
quecontieneloscamposdedatos:

<form>
<header>
<!Buttonsgohere>
</header>
<sheet>
<!Contentgoeshere:>
<fieldname="name"/>
<fieldname="is_done"/>
</sheet>
</form>

Agregarbotonesdeaccin
Losformulariospuedentenerbotonesqueejecutenacciones.Estossoncapacesdedesencadenaracciones
deflujodetrabajo,ejecutarAccionesdeVentana,comoabrirotroformulario,oejecutarfuncionesPython
definidasenelmodelo.
Estospuedensercolocadosencualquierpartedentrodeunformulario,peroparaformulariosconestilode
documentos,elsitiorecomendadoesenlaseccin <header> .
Paranuestraaplicacin,agregaremosdosbotonesparaejecutarmtodosdelmodelo todo.task :

Paranuestraaplicacin,agregaremosdosbotonesparaejecutarmtodosdelmodelo todo.task :

<header>
<buttonname="do_toggle_done"type="object"string="ToggleDone"class="oe_highlight"
<buttonname="do_clear_done"type="object"string="ClearAllDone"/>
</header>

Losatributosbsicosparaunbotnson: string coneltextoquesemuestraenelbotn, type quehace


referenciaaltipodeaccinqueejecuta,y name queeselidentificadorparaesaaccin.El
atributo class puedeaplicarestilosCSS,comounHTMLcomn.
Organizarformulariosusandogrupos
Laetiqueta <group> permiteorganizarelcontenidodelformulario.Colocandoloselementos <group> dentro
deunelemento <group> creaunadisposicindedoscolumnasdentrodelgrupoexterno.Serecomiendaque
loselementosGrouptenganunnombreparahacermsfcilsuextensinenotrosmdulos.
Usaremosestoparamejorarlaorganizacindenuestrocontenido.Cambiemoselcontenidode <sheet> de
nuestroformulario:

<sheet>
<groupname="group_top">
<groupname="group_left">
<fieldname="name"/>
</group>
<groupname="group_right">
<fieldname="is_done"/>
<fieldname="active"readonly="1"/>
</group>
</group>
</sheet>

Lavistadeformulariocompleta
Enestemomento,nuestroregistroen todo_view.xml paralavistadeformulariode todo.task deberalucir
as:

<recordid="view_form_todo_task"model="ir.ui.view">
<fieldname="name">TodoTaskForm</field>
<fieldname="model">todo.task</field>
<fieldname="arch"type="xml">
<form>
<header>
<buttonname="do_toggle_done"type="object"string="ToggleDone"class="oe
<buttonname="do_clear_done"type="object"string="ClearAllDone"/>
</header>
<sheet>
<groupname="group_top">

<groupname="group_left">
<fieldname="name"/>
</group>
<groupname="group_right">
<fieldname="is_done"/>
<fieldname="active"readonly="1"/>
</group>
</group>
</sheet>
</form>
</field>
</record>

RecuerdequeparaqueloscambiostenganefectoenlabasededatosdeOdoo,esnecesarioactualizarel
mdulo.Paraverloscambioenelclienteweb,esnecesariovolveracargarelformulario:haciendo
nuevamenteclicenlaopcindemenqueabreelformulario,ovolviendoacargarlapginaenelnavegador
(F5enlamayoradelosnavegadores).
Ahora,agreguemoslalgicadenegocioparalasaccionesdelosbotones.

Agregarvistasdelistaybsqueda
Cuandounmodelosevisualizacomounalista,seestausandounavista <tree> Lasvistasderbolson
capacesdemostrarlneasorganizadasporjerarqua,perolamayoradelasvecessonusadaspara
desplegarlistasplanas.
Podemosagregarlasiguientedefinicindeunavistaderbola todo_view.xml :

<recordid="view_tree_todo_task"model="ir.ui.view">
<fieldname="name">TodoTaskTree</field>
<fieldname="model">todo.task</field>
<fieldname="arch"type="xml">
<treecolors="gray:is_done==True">
<fieldname="name"/>
<fieldname="is_done"/>
</tree>
</field>
</record>
Hemosdefinidounalistaconsolodoscolumnas, name y is_done .Tambinagregamosuntoqueextra:las
lneasparalastareasfinalizadas( is_done==True )sonmostradasencolorgris.
EnlapartesuperiorderechadelalistaOdoomuestraunacampodebsqueda.Loscamposdebsqueda
predefinidosylosfiltrosdisponiblespuedenserpredeterminadosporunavista <search> .
Comolohicimosanteriormente,agregaremosestoa todo_view.xml :

<recordid="view_filter_todo_task"model="ir.ui.view">
<fieldname="name">TodoTaskFilter</field>

<fieldname="model">todo.task</field>
<fieldname="arch"type="xml">
<search>
<fieldname="name"/>
<filterstring="NotDone"domain="[('is_done','=',False)]"/>
<filterstring="Done"domain="[('is_done','!=',False)]"/>
</search>
</field>
</record>
Loselementos <field> definencamposquetambinsonbuscadoscuandoseescribeenelcampode
bsqueda.Loselementos <filter> agregancondicionespredefinidasdefiltro,usandolasintaxisdedominio
quepuedeserseleccionadaporelusuarioolausuariaconunclic.

Agregarlalgicadenegocio
Ahoraagregaremoslgicaanuestrosbotones.EditeelarchivoPython todo_model.py paraagregaralaclase
losmtodosllamadosporlosbotones.
UsaremoslaAPInuevaintroducidaenOdoo8.0.Paracompatibilidadconversionesanteriores,deforma
predeterminadaOdooesperalaAPIanterior,porlotantoparacrearmtodosusandolaAPInuevase
necesitanenellosdecoradoresPython.Primeronecesitamosunadeclaracin import alprincipiodelarchivo:

fromopenerpimportmodels,fields,api
LaaccindelbotnToggleDoneesbastantesimple:solocambiadeestado(marcaodesmarca)lasealIs
Done?.Laformamssimpleparaagregarlalgicaaunregistro,esusareldecorador @api.one .
Aqu self representaraunregistro.Silaaccinesllamadaparaunconjuntoderegistros,laAPIgestionara
estolanzandoelmtodoparacadaunodelosregistros.
Dentrodelaclase TodoTask agregue:

@api.onedefdo_toggle_done(self):
self.is_done=notself.is_done
returnTrue
Comopuedeobservar,simplementemodificaelcampo is_done ,invirtiendosuvalor.Luegolosmtodos
puedenserllamadosdesdeelladodelclientysiempredebendevolveralgo.Sinodevuelvennada,las
llamadasdelclienteusandoelprotocoloXMLRPCnofuncionar.Sinotenemosnadaquedevolver,laprctica
comnessimplementedevolver True .
Despusdeesto,sireiniciamoselservidorOdooparacargarnuevamenteelarchivoPython,elbotnToggle
Donedebefuncionar.
ParaelbotnClearAllDonequeremosirunpocomslejos.Estedebebuscartodoslosregistrosactivosque
estnfinalizados,ydesactivarlos.Sesuponequelosbotonesdeformulariosoloactansobrelosregistros
seleccionados,peroparamantenerlascosassimplesharemosunpocodetrampa,ytambinactuarsobre
losdemsbotones:

@api.multidefdo_clear_done(self):
done_recs=self.search([('is_done','=',True)])

done_recs.write({'active':False})
returnTrue
Enlosmtodosdecoradoscon @api.multi el self representaunconjuntoderegistros.Puedecontenerun
nicoregistro,cuandoseusadesdeunformulario,omuchosregistros,cuandoseusadesdelavistadelista.
Ignoraremoselconjuntoderegistrosde self yconstruiremosnuestropropioconjunto done_recs que
contienetodaslatareasmarcadascomofinalizadas.Luegofijamoslasealactivacomo False ,entodas
ellas.
El search esunmtododelaAPIquedevuelvelosregistrosquecumplenconalgunascondiciones.Estas
condicionessonescritasenundominio,estoesunalistadetros.Exploraremosconmayordetallelos
dominiosmsadelante.
Elmtodo write fijalosvaloresdetodosloselementosenelconjuntodeunavez.Losvaloresaescribirson
definidosusandoundiccionario.Usar write aquesmseficientequeiteraratravsdeunconjuntode
registrosparaasignarelvalorunoporuno.
Noteque @api.one noeslomseficienteparaestasacciones,yaqueseejecutarparacadaunodelos
registrosseleccionados.La @api.multi seaseguraquenuestrocdigoseaejecutadounasolavezinclusosi
haymsdeunregistroseleccionado.Estopuedepasarsiunaopcinesagregadaalavistadelista.

Configurandolaseguridadenelcontroldeacceso
Debehabernotado,desdequecargamosnuestromdulo,unmensajedealertaenenregistrodel
servidor:Themodeltodo.taskhasnoaccessrules,consideraddingone.
Elmensajeesmuyclaro:nuestromodelonuevonotienereglasdeacceso,porlotantopuedeserusadopor
cualquiera,nosoloporeladministrador.Comosperusuarioel admin ignoralasreglasdeacceso,porello
somoscapacesdeusarelformulariosinerrores.Perodebemosarreglarestoantesqueotrosusuarios
puedanusarlo.
Paratenerunamuestradelainformacinrequeridaparaagregarreglasdeaccesoaunmodelo,useel
clientewebydirjasea:Configuracin|Tcnico|Seguridad|Listacontrolesdeacceso.

Grfico2.4ListacontrolesdeaccesodeOdoo
AqupodemosverlaACLparaelmodelo mail.mail .Esteindica,porgrupo,lasaccionespermitidasenlos
registros.
Estainformacindebeserprovistaporelmodelo,usandounarchivodedatosparacargarlaslneasdentro
delmodelo ir.model.access .Daremosaccesocompletoalmodeloalgrupoempleado.Empleadoeselgrupo
bsicodeacceso,casitodospertenecenaestegrupo.
EstoesrealizadousualmenteusandounarchivoCSVllamado security/ir.model.access.csv .Losmodelos
generanidentificadoresautomticamente:para todo.task elidentificadores model_todo_task .Losgrupos
tambintienenidentificadoresfijadosporlosmodelosqueloscrean.Elgrupoempleadoescreadoporel
mdulobaseytieneelidentificador base.group_user .Elnombredelalneaessoloinformativoyesmejorsi
esnico.Losmdulosrazusandounacadenaseparadaporpuntosconelnombredelmodeloyelnombre
delgrupo.Siguiendoestaconvencinusaremos todo.task.user .

Ahoraquetenemostodoloquenecesitamossaber,vamosaagregarelarchivonuevoconelsiguiente
contenido:

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_todo_task_group_user,todo.task.user,model_todo_task,base.group_user,1,1,1,1
Nodebemosolvidaragregarlareferenciaaestearchivonuevoenelatributo"data"deldescriptor
en __openerp__.py ,delasiguientemanera:

'data':[
'todo_view.xml',
'security/ir.model.access.csv',
],
Comosehizoanteriormente,actualiceelmduloparaqueestoscambiostenganefecto.Elmensajede
advertenciadeberadesaparecer,ypuedeconfirmarquelospermisosseancorrectosaccediendoconla
cuentadeusuariodemo(lacontraseaestambindemo)eintentarejecutarlacaractersticade"todotasks".

Reglasdeaccesodeniveldefila
Odooesunsistemamultiusuario,yqueremosquelaaplicacintodotaskseaprivadaparacadausuario.
Afortunadamente,Odoosoportareglasdeaccesodeniveldefila.EnelmenTcnicopuedenencontrarse
enlaopcinReglasdeRegistro,juntoalaListadeControldeAcceso.Lasreglasderegistrosondefinidas
enelmodelo ir.rule .Comoescostumbre,necesitamosunnombredistintivo.Tambinnecesitamosel
modeloenelcualoperanyeldominioparaforzarlarestriccindeacceso.Elfiltrodedominiousalamisma
sintaxisdedominiomencionadaanteriormente,yusadoalolargodeOdoo.
Finalmente,lasreglaspuedenserglobales(elcampo global esfijadoa True )osoloparagrupos
particularesdeseguridad.Ennuestrocaso,puedeserunareglaglobal,peroparailustrarelcasomscomn,
laharemoscomounareglaespecficaparaungrupo,aplicadasoloalgrupoempleados.
Debemoscrearunarchivo security/todo_access_rules.xml conelsiguientecontenido:

<?xmlversion="1.0"encoding="utf8"?>
<openerp>
<datanoupdate="1">
<recordid="todo_task_user_rule"model="ir.rule">
<fieldname="name">ToDoTasksonlyforowner</field>
<fieldname="model_id"ref="model_todo_task"/>
<fieldname="domain_force">
[('create_uid','=',user.id)]
</field>
<fieldname="groups"eval="[(4,ref('base.group_user'))]"/>
</record>
</data>
</openerp>
Notaelatributo noupdate="1" .Estosignificaqueestosdatosnosernactualizadosenlasactualizacionesdel
mdulo.Estopermitirqueseapersonalizadamasadelante,debidoaquelasactualizacionesdelmdulono
destruirnloscambiosrealizados.Perotenencuentaqueestoserasmientrasseestdesarrollando,porlo
tantoesprobablequequierasfijar noupdate="0" duranteeldesarrollo,hastaqueestsfelizconelarchivode

tantoesprobablequequierasfijar noupdate="0" duranteeldesarrollo,hastaqueestsfelizconelarchivode


datos.
Enelcampo groups tambinencontrarasunaexpresinespecial.Esuncampoderelacinunoamuchos,y
tienenunasintaxisespecialparaoperarconellos.Enestecasolatupla (4,x) indicaagregar x alos
registros,y x esunareferenciaalgrupoempleados,identificadopor base.group_user .
Comosehizoanteriormente,debemosagregarelarchivoa __openerp__.py antesquepuedasercargadoal
mdulo:

'data':[
'todo_view.xml',
'security/ir.model.access.csv',
'security/todo_access_rules.xml',
],

Agregarunconoalmdulo
Nuestromdulosevegenial.Porqunoaadirunconoparaqueseveaanmejor?.Paraestosolo
debemosagregaralmduloelarchivo static/description/icon.png conelconoqueusaremos.
Lossiguientescomandosagreganunconocopiadodelmduloraz Notes :

$mkdirp~/odoodev/customaddons/todo_app/static/description
$cd~/odoodev/customaddons/todo_app/static/description
$cp../odoo/addons/note/static/description/icon.png./
Ahora,siactualizamoslalistademdulos,nuestromdulodebemostrarseconelcononuevo.

Resumen
Creamosunmdulonuevodesdecero,cubriendoloselementosmsfrecuentementeusadosenunmdulo:
modelos,lostrestiposbasedevistas(formulario,listaybsqueda),lalgicadenegocioenlosmtodosdel
modelo,yseguridadenelacceso.
Enelproceso,sefamiliarizconelprocesodedesarrollodemdulos,elcualincluyelaactualizacindel
mduloylaaplicacindereiniciodelservidorparahacerefectivosenOdooloscambiosgraduales.
Recuerdesiempre,alagregarcamposenelmodelo,queesnecesariaunaactualizacindelmdulo.Cuando
secambiaelcdigoPython,incluyendoelarchivodemanifiesto,esnecesariounreiniciodelservidor.Cuando
secambianarchivosXMLoCSVesnecesariaunaactualizacindelmduloinclusoencasodeduda,realice
ambas:actualizacindelmduloyreiniciodelservidor.
Enelsiguientecaptulo,seaprendersobrelaconstruccindemdulosqueseacoplanaotroexistentespara
agregarcaractersticas.

Вам также может понравиться