Odoo Help

0

I can't find where the error is

By
Uillino
on 9/1/15, 4:10 PM 1,246 views

I'm writing a module that was working fine. Suddenly, an error is raised, but I'm not able to understand what I've done.

This is my py file:

# -*- encoding: utf-8 -*-
from openerp import models, fields, api
from openerp.osv import osv
from datetime import date
from openerp.tools.translate import _
import re

class bridge_contratto(models.Model):
_name = 'tbl_contratto'
_description = 'Classe per l\'inserimento in tbl_contratto'

state = fields.Selection([
('contratto', 'Contratto'),
('responsabile', 'Responsabile')
], 'Status', required=True, copy=False)
scode_contratto = fields.Char('Codice Contratto', size=3, help="Inserisci il codice contratto", required=True)
sdescrizione_breve_contratto = fields.Char('Descrizione Breve', size=40, help="Inserisci una breve descrizione del contratto", required=True)
sdescrizione_contratto = fields.Text('Descrizione Estesa', help="Inserisci la descrizione estesa del contratto", required=True)
date_start = fields.Date('Data Inizio Contratto', required=True)
date_end = fields.Date('Data Fine Contratto', required=True)
dt_ini_prol = fields.Date('Data Inizio Prolungamento')
dt_fine_prol = fields.Date('Data Fine Prolungamento')
date_agg = fields.Date('Data Aggiornamento')
data_end_effe = fields.Date('Data Effettiva di Fine')
codice_sipai = fields.Char('Codice SIPAI', size=10, help="Inserisci il Codice SIPAI", required=True)
codice_cig = fields.Char('Codice CIG', size=9, help="Inserisci il Codice CIG nel formato X123/aaaa", required=True)

_defaults = {
#'date_start': date.today().strftime('%Y-%m-%d'),
'state': 'contratto',}

# controllo che il campo scode_contratto sia formato esclusivamente da numeri e che sia composto
# da 3 caratteri.
def controllo_scode_contratto(self, cr, uid, ids, scode_contratto, context=None):
if scode_contratto and not unicode.isdigit(scode_contratto):
My_error_Msg = 'Il campo Codice Contratto può contenere solo numeri'
raise osv.except_osv(("Attenzione!"), (My_error_Msg))
return scode_contratto
elif scode_contratto and len(str(scode_contratto)) != 3:
My_error_Msg = 'La lunghezza del campo Codice Contratti deve essere di 3 cifre'
raise osv.except_osv(("Attenzione!"), (My_error_Msg))
return scode_contratto
else:
return scode_contratto

# effettuo il controllo su scode_contratto mediante onchange
def onchange_controllo_scode_contratto_id(self, cr, uid, ids, scode_contratto, context=None):
res = {
'value':{
'scode_contratto': self.controllo_scode_contratto(cr, uid, ids, scode_contratto, context=context)
}

}
return res

# sdescrizione_breve_contratto deve essere tutto in maiuscolo
def onchange_uppercase(self, cr, uid, ids, sdescrizione_breve_contratto, context=None):
# l'if serve perché, se non ci fosse, Odoo inserirebbe un False nel campo sdescrizione_breve_contratto
if sdescrizione_breve_contratto:
result = {
'value': {
'sdescrizione_breve_contratto': str(sdescrizione_breve_contratto).upper()
}
}
return result

# sdescrizione_contratto deve avere la prima lettera maiuscola e le altre minuscole
def onchange_capitalize(self, cr, uid, ids, sdescrizione_contratto, context=None):
if sdescrizione_contratto:
result = {
'value': {
'sdescrizione_contratto': str(sdescrizione_contratto).capitalize()
}
}
return result

#controllo successione date
@api.one
@api.constrains('date_start', 'date_end', 'dt_ini_prol', 'dt_fine_prol', 'data_end_effe')
def controllo_successione_date(self):
if self.date_start > self.date_end:
raise Warning(_("Attenzione!\n La Data di Fine Contratto (%s) è precedente alla Data di Inizio Contratto (%s)") % (self.date_end, self.date_start))
elif self.dt_ini_prol is not False and self.date_end > self.dt_ini_prol:
raise Warning(_("Attenzione!\n La Data di Inizio Prolungamento (%s) è precedente alla Data di Fine Contratto (%s)") % (self.dt_ini_prol, self.date_start))
elif self.dt_fine_prol is not False and self.dt_ini_prol > self.dt_fine_prol:
raise Warning(_("Attenzione!\n La Data di Fine Prolungamento (%s) è precedente alla Data di Inizio Prolungamento (%s)") % (self.dt_fine_prol, self.dt_ini_prol))
elif (self.dt_ini_prol and not self.dt_fine_prol) or (self.dt_fine_prol and not self.dt_ini_prol):
raise Warning(_("Attenzione!\n Attenzione: devi inserire sia la data di inizio che di fine prolungamento"))
elif self.data_end_effe is not False and self.date_start > self.data_end_effe:
raise Warning(_("Attenzione!\n La Data Effettiva di Fine (%s) è precedente alla Data Inizio Contratto (%s)") % (self.data_end_effe, self.date_start))
elif self.data_end_effe is not False and self.dt_ini_prol is not False and self.dt_ini_prol > self.data_end_effe:
raise Warning(_("Attenzione!\n La Data Effettiva di Fine (%s) è precedente alla Data Inizio Prolungamento (%s)") % (self.data_end_effe, self.dt_ini_prol))

# controllo codice cig: il primo carattere deve essere una lettera, il quinto '/' e i restanti
# numeri
@api.one
@api.constrains('codice_cig')
def controllo_codice_cig(self):
i=0
a=1
while i<9:
if i==0:
if unicode.isdigit(self.codice_cig[0]):
a=i+1
raise Warning(("ATTENZIONE!\nIl %s° carattere del Codice CIG deve essere una lettera") % (a))
elif i in range (1,4) or i in range (5,10):
if not unicode.isdigit(self.codice_cig[i]):
raise Warning(('ATTENZIONE!\nIl %s° carattere del Codice CIG deve essere un numero') % (a))
elif i == 4:
if self.codice_cig[i] != '/':
raise Warning(("ATTENZIONE!\nIl %s° carattere del Codice CIG deve essere '/'") % (a))
i=i+1
a=a+1

# le lettere del codice sipai devono essere maiuscole
def uppercase(self, cr, uid, ids, codice_cig, context=None):
if codice_cig:
return str(codice_cig).upper()

def onchange_controllo_codice_cig_id(self, cr, uid, ids, codice_cig, context=None):
res = {
'value':{
'codice_cig': self.uppercase(cr, uid, ids, codice_cig, context=context)
}
}
return res

# #controllo che siano stati compilati entrambi i campi data
# def controllo_dt(self, cr, uid, ids, context=None):
# for item in self.browse(cr, uid, ids, context=context):
# if (item.dt_ini_prol and not item.dt_fine_prol) or (item.dt_fine_prol and not item.dt_ini_prol):
# return False
# return True

# _constraints = [
# (controllo_date_end, 'Attenzione: la data di fine contratto è precedente alla data di inizio contratto', ['date_start','date_end']),
# (controllo_dt_ini_prol, 'Attenzione: la data di inizio prolungamento è precedente alla data di fine contratto', ['dt_ini_prol','date_end']),
# (controllo_dt_fine_prol, 'Attenzione: la data di fine prolungamento è precedente alla data di inizio prolungamento', ['dt_ini_prol','dt_fine_prol']),
# (controllo_dt, 'Attenzione: devi inserire sia la data di inizio che di fine prolungamento', ['dt_ini_prol','dt_fine_prol']),
# ]

_sql_constraints = [
('scode_contratto',
'unique(scode_contratto)',
'Attenzione! Hai scelto un Codice Contratto già esistente.\n Per favore, inseriscine uno diverso.'),
('sdescrizione_breve_contratto',
'unique(sdescrizione_breve_contratto)',
'Attenzione! La Descrizione Breve inserita è già stata utilizzata per un altro contratto.\n Per favore, inseriscine una diversa.'),
('sdescrizione_contratto',
'unique(sdescrizione_contratto)',
'Attenzione! La Descrizione inserita è già stata utilizzata per un altro contratto.\n Per favore, inseriscine una diversa.')
]

#utilizzo l'id di tbl_contratto come chiave esterna per tbl_responsabile
@api.multi
def open_responsabile(self):
ac = self.env['ir.model.data'].xmlid_to_res_id('mymodule.view_bridge_responsabile_form', raise_if_not_found=True)
tbl_contratto = False
for o in self:
tbl_contratto = o.id
result = {
'name': '2nd class',
'view_type': 'form',
'res_model': 'tbl_responsabile',
'view_id': ac,
'context': {'default_id_tbl_contratto': tbl_contratto},
'type': 'ir.actions.act_window',
'view_mode': 'form'
}
return result

class bridge_responsabile(models.Model):
_name = 'tbl_responsabile'
_description = 'Classe per l\'inserimento in tbl_responsabile'

# eredito l'id di modello tbl_contratton, che rinomino in id_tbl_contratto
_inherits = {'tbl_contratto': 'id_tbl_contratto'}

# l'id di tbl_contratto è foreign key per id_tbl_contratto (1:N)
id_tbl_contratto = fields.Many2one('tbl_contratto', 'Codice Contratto', widget="many2one_list")

responsabile_sogei = fields.Boolean(string='Responsabile Sogei', help="Seleziona se il responsabile è SOGEI")
responsabile_fornitore = fields.Boolean(string='Responsabile Fornitore', help="Seleziona se il responsabile è il fornitore")
responsabile_contratto = fields.Char(string='Responsabile Contratto', size=100, help="Indica il responsabile del contratto", required=True)
tel_responsabile_contratto = fields.Char(string='Telefono Responsabile Contratto', size=11, help="Inserisci il numero di telefono del responsabile del contratto")
email_resp_contratto = fields.Char(string='Email del Responsabile Contratto', help="Inserisci l'indirizzo email del responsabile del contratto", required=True)

# controllo che tel_responsabile_contratto sia composto solo da numeri
@api.one
@api.constrains('tel_responsabile_contratto')
def controllo_tel_responsabile_contratto(self):
if self.tel_responsabile_contratto and unicode.isdigit(self.tel_responsabile_contratto) is False:
raise Warning("ATTENZIONE!\nIl telefono del responsabile del contratto può essere composto solo da numeri")

# controllo che email_resp_contratto sia un indirizzo email
@api.one
@api.constrains('email_resp_contratto')
def controllo_email_resp_contratto(self):
if not re.match(r"^[A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z0-9]", self.email_resp_contratto):
raise Warning("ATTENZIONE!\nL'indirizzo email del responsabile del contratto non è valido")

and this is my view:

<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>

<!-- Creo la vista nel formato lista, disabilito il tasto export, rinominando il campo
write_date e visualizzo la data in formato Date-->
<record id="view_bridge_contratto_tree" model="ir.ui.view">
<field name="name">bridge.contratto.tree.view</field>
<field name="model">tbl_contratto</field>
<field name="arch" type="xml">
<tree string="Bridge" export="false">
<field name="id"/>
<field name="scode_contratto"/>
<field name="sdescrizione_breve_contratto"/>
<field name="sdescrizione_contratto"/>
<field name="date_start"/>
<field name="date_end"/>
<field name="dt_ini_prol"/>
<field name="dt_fine_prol"/>
<field name="date_agg"/>
<field name="data_end_effe"/>
<field name="codice_sipai"/>
<field name="codice_cig"/>
<field name="write_date" string="Data ultima modifica" widget="date"/>
</tree>
</field>
</record>

<!-- Creo la vista nel formato form, disabilitao il tasto duplicate, rinomino il campo write_date
che visualizzo in formato Date, inibisco la visualizzazione dei campi id e write_date all'atto della
creazione di una nuova riga e applico la funzione onchange_controllo_scode_contratto_id a
scode_contrallo, uppercase a sdescrizione_breve_contratto e capitalize a sdescrizione_contratto -->
<record id="view_bridge_contratto_form" model="ir.ui.view">
<field name="name">bridge.contratto.form.view</field>
<field name="model">tbl_contratto</field>
<field name="arch" type="xml">
<form string="Bridge" duplicate="false">
<header>
<group>
<group>
<!-- Creo un bottone che mi consente di aprire direttamente il form per l'inserimento
dei dati del responsabile, chiamando il metodo open_responsabile -->
<!-- <button name="%(action_bridge_inserimento_responsabile)d" type="action" string="Submit" /> -->
<button name="open_responsabile" type="object" string="Salva e vai alla tabella Responsabile" />
</group>
<group>
<field name="state" widget="statusbar" statusbar_visible="contratto,responsabile" statusbar_colors='{"contratto":"blue"}' readonly="1"/>
</group>
</group>
</header>
<sheet>
<group>
<field name="id" attrs="{'invisible': [('write_date', '=', False)]}" />
<field name="scode_contratto" on_change="onchange_controllo_scode_contratto_id(scode_contratto)"/>
<field name="sdescrizione_breve_contratto" on_change="onchange_uppercase(sdescrizione_breve_contratto)"/>
<field name="sdescrizione_contratto" on_change="onchange_capitalize(sdescrizione_contratto)"/>
<field name="date_start"/>
<field name="date_end"/>
<field name="dt_ini_prol"/>
<field name="dt_fine_prol"/>
<field name="date_agg"/>
<field name="data_end_effe"/>
<field name="codice_sipai"/>
<field name="codice_cig" on_change="onchange_controllo_codice_cig_id(codice_cig)"/>
<field name="write_date" string="Data ultima modifica" attrs="{'invisible': [('write_date', '=', False)]}" widget="date"/>
</group>
</sheet>
</form>
</field>
</record>

<!-- Creo l'azione Attività (action_bridge_attivita) -->
<record id="action_bridge_contratto" model="ir.actions.act_window">
<field name="name">Contratto</field>
<field name="res_model">tbl_contratto</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" eval="False"/>
</record>

<!-- Inserisco l'azione action_bridge_contratto nel menu Messaging -->
<menuitem action="action_bridge_contratto" id="menu_action_bridge_contratto" parent="mail.mail_feeds" sequence="140"/>


<!-- Creo la vista nel formato lista, disabilito il tasto export, rinominando il campo
write_date e visualizzo la data in formato Date-->
<record id="view_bridge_responsabile_tree" model="ir.ui.view">
<field name="name">bridge.responsabile.tree.view</field>
<field name="model">tbl_responsabile</field>
<field name="arch" type="xml">
<tree string="Bridge" export="false">
<field name="id"/>
<field name="id_tbl_contratto" readonly="1"/>
<field name="responsabile_sogei"/>
<field name="responsabile_fornitore"/>
<field name="responsabile_contratto"/>
<field name="tel_responsabile_contratto"/>
<field name="email_resp_contratto" widget="email"/>
<field name="write_date" string="Data ultima modifica" widget="date"/>
</tree>
</field>
</record>

<!-- Creo la vista nel formato form, disabilitao il tasto duplicate, rinomino il campo write_date
che visualizzo in formato Date, inibisco la visualizzazione dei campi id e write_date all'atto della
creazione di una nuova riga. -->
<record id="view_bridge_responsabile_form" model="ir.ui.view">
<field name="name">bridge.responsabile.form.view</field>
<field name="model">tbl_responsabile</field>
<field name="arch" type="xml">
<form string="Bridge" duplicate="false">
<group>
<field name="id" attrs="{'invisible': [('write_date', '=', False)]}" />
<field name="id_tbl_contratto"/>
<field name="responsabile_sogei"/>
<field name="responsabile_fornitore"/>
<field name="responsabile_contratto"/>
<field name="tel_responsabile_contratto"/>
<field name="email_resp_contratto" widget="email"/>
<field name="write_date" string="Data ultima modifica" attrs="{'invisible': [('write_date', '=', False)]}" widget="date"/>
</group>
</form>
</field>
</record>

<!-- Creo l'azione Inserimento Responsabile (inserimento_responsabile) per inserire direttamente i dati
del responsabile -->
<record id="action_bridge_inserimento_responsabile" model="ir.actions.act_window">
<field name="name">Inserimento.Responsabile</field>
<field name="res_model">tbl_responsabile</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_bridge_responsabile_form"></field>
</record>

<!-- Creo l'azione Responsabile (action_bridge_responsabile_) -->
<record id="action_bridge_responsabile_" model="ir.actions.act_window">
<field name="name">Responsabile</field>
<field name="res_model">tbl_responsabile</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" eval="False"/>
</record>

<!-- Inserisco l'azione action_bridge_responsabile nel menu Messaging -->
<menuitem action="action_bridge_responsabile_" id="menu_action_bridge_responsabile" parent="mail.mail_feeds" sequence="150"/>

</data>
</openerp>

I get this error:

2015-09-01 20:01:44,285 7266 INFO Bridge openerp.modules.loading: loading 59 modules...
2015-09-01 20:01:44,615 7266 WARNING Bridge openerp.models: Field definition for _inherits reference "id_tbl_contratto" in "tbl_responsabile" must be marked as "required" with ondelete="cascade" or "restrict", forcing it to required + cascade.
2015-09-01 20:01:44,619 7266 WARNING Bridge openerp.models: Field definition for _inherits reference "mod_id" in "big.test" must be marked as "required" with ondelete="cascade" or "restrict", forcing it to required + cascade.
2015-09-01 20:01:44,905 7266 INFO Bridge openerp.modules.module: module mymodule: creating or updating database tables
/home/odoo/models.py:458: UnicodeWarning: Unicode unequal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
if cols[k][key] != vals[key]:
2015-09-01 20:01:45,267 7266 INFO Bridge openerp.modules.loading: loading mymodule/attivita_servizio_view.xml
2015-09-01 20:01:45,455 7266 INFO Bridge openerp.modules.loading: loading mymodule/cicli_fasi_prodotti_view.xml
2015-09-01 20:01:45,706 7266 INFO Bridge openerp.modules.loading: loading mymodule/macro_sotto_view.xml
2015-09-01 20:01:45,882 7266 INFO Bridge openerp.modules.loading: loading mymodule/inserimento_view.xml
2015-09-01 20:01:46,106 7266 INFO Bridge werkzeug: 127.0.0.1 - - [01/Sep/2015 20:01:46] "GET /web HTTP/1.1" 500 -
2015-09-01 20:01:46,141 7266 ERROR Bridge werkzeug: Error on request:
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/Werkzeug-0.9-py2.7.egg/werkzeug/serving.py", line 174, in run_wsgi
execute(self.server.app)
File "/usr/lib/python2.7/site-packages/Werkzeug-0.9-py2.7.egg/werkzeug/serving.py", line 162, in execute
application_iter = app(environ, start_response)
File "/home/odoo/service/server.py", line 281, in app
return self.app(e, s)
File "/home/odoo/service/wsgi_server.py", line 216, in application
return application_unproxied(environ, start_response)
File "/home/odoo/service/wsgi_server.py", line 202, in application_unproxied
result = handler(environ, start_response)
File "/home/odoo/http.py", line 1280, in __call__
return self.dispatch(environ, start_response)
File "/home/odoo/http.py", line 1254, in __call__
return self.app(environ, start_wrapped)
File "/usr/lib/python2.7/site-packages/Werkzeug-0.9-py2.7.egg/werkzeug/wsgi.py", line 574, in __call__
return self.app(environ, start_response)
File "/home/odoo/http.py", line 1412, in dispatch
ir_http = request.registry['ir.http']
File "/home/odoo/http.py", line 339, in registry
return openerp.modules.registry.RegistryManager.get(self.db) if self.db else None
File "/home/odoo/modules/registry.py", line 335, in get
update_module)
File "/home/odoo/modules/registry.py", line 366, in new
openerp.modules.load_modules(registry._db, force_demo, status, update_module)
File "/home/odoo/modules/loading.py", line 351, in load_modules
force, status, report, loaded_modules, update_module)
File "/home/odoo/modules/loading.py", line 255, in load_marked_modules
loaded, processed = load_module_graph(cr, graph, progressdict, report=report, skip_modules=loaded_modules, perform_checks=perform_checks)
File "/home/odoo/modules/loading.py", line 176, in load_module_graph
_load_data(cr, module_name, idref, mode, kind='data')
File "/home/odoo/modules/loading.py", line 118, in _load_data
tools.convert_file(cr, module_name, filename, idref, mode, noupdate, kind, report)
File "/home/odoo/tools/convert.py", line 901, in convert_file
convert_xml_import(cr, module, fp, idref, mode, noupdate, report)
File "/home/odoo/tools/convert.py", line 987, in convert_xml_import
obj.parse(doc.getroot(), mode=mode)
File "/home/odoo/tools/convert.py", line 853, in parse
self._tags[rec.tag](self.cr, rec, n, mode=mode)
File "/home/odoo/tools/convert.py", line 757, in _tag_record
f_val = _eval_xml(self,field, self.pool, cr, self.uid, self.idref)
File "/home/odoo/tools/convert.py", line 177, in _eval_xml
for n in node]), idref)
File "/home/odoo/tools/convert.py", line 166, in _process
idref[id] = self.id_get(cr, id)
File "/home/odoo/tools/convert.py", line 832, in id_get
res = self.model_id_get(cr, id_str, raise_if_not_found)
File "/home/odoo/tools/convert.py", line 843, in model_id_get
raise_if_not_found=raise_if_not_found)
File "/home/odoo/api.py", line 241, in wrapper
return old_api(self, *args, **kwargs)
File "/home/odoo/addons/base/ir/ir_model.py", line 932, in xmlid_to_res_model_res_id
return self.xmlid_lookup(cr, uid, xmlid)[1:3]
File "/home/odoo/api.py", line 241, in wrapper
return old_api(self, *args, **kwargs)
File "<string>", line 2, in xmlid_lookup

File "/home/odoo/tools/cache.py", line 71, in lookup
value = d[key] = self.method(*args, **kwargs)
File "/home/odoo/addons/base/ir/ir_model.py", line 922, in xmlid_lookup
raise ValueError('External ID not found in the system: %s' % (xmlid))
ParseError: "External ID not found in the system: mymodule.action_bridge_inserimento_responsabile" while parsing /home/odoo/addons/mymodule/inserimento_view.xml:33, near
<record id="view_bridge_contratto_form" model="ir.ui.view">
<field name="name">bridge.contratto.form.view</field>
<field name="model">tbl_contratto</field>
<field name="arch" type="xml">
<form string="Bridge" duplicate="false">
<header>
<group>
<group>
<!-- Creo un bottone che mi consente di aprire direttamente il form per l'inserimento
dei dati del responsabile, chiamando il metodo open_responsabile -->
<!-- <button name="%(action_bridge_inserimento_responsabile)d" type="action" string="Submit" /> -->
<button name="open_responsabile" type="object" string="Salva e vai alla tabella Responsabile"/>
</group>
<group>
<field name="state" widget="statusbar" statusbar_visible="contratto,responsabile" statusbar_colors="{&quot;contratto&quot;:&quot;blue&quot;}" readonly="1"/>
</group>
</group>
</header>
<sheet>
<group>
<field name="id" attrs="{'invisible': [('write_date', '=', False)]}"/>
<field name="scode_contratto" on_change="onchange_controllo_scode_contratto_id(scode_contratto)"/>
<field name="sdescrizione_breve_contratto" on_change="onchange_uppercase(sdescrizione_breve_contratto)"/>
<field name="sdescrizione_contratto" on_change="onchange_capitalize(sdescrizione_contratto)"/>
<field name="date_start"/>
<field name="date_end"/>
<field name="dt_ini_prol"/>
<field name="dt_fine_prol"/>
<field name="date_agg"/>
<field name="data_end_effe"/>
<field name="codice_sipai"/>
<field name="codice_cig" on_change="onchange_controllo_codice_cig_id(codice_cig)"/>
<field name="write_date" string="Data ultima modifica" attrs="{'invisible': [('write_date', '=', False)]}" widget="date"/>
</group>
</sheet>
</form>
</field>
</record>

Could anyone help me finding the error?

2
Axel Mendoza
On 9/1/15, 4:48 PM

Your action "action_bridge_inserimento_responsabile" is defined latter in the xml file, you should move it before the record "view_bridge_contratto_form" and it will be ok

Thank you!

Uillino
on 9/1/15, 6:50 PM

Thanks for the up vote, happy to help

Axel Mendoza
on 9/1/15, 7:07 PM

About This Community

This platform is for beginners and experts willing to share their Odoo knowledge. It's not a forum to discuss ideas, but a knowledge base of questions and their answers.

Register

Odoo Training Center

Access to our E-learning platform and experience all Odoo Apps through learning videos, exercises and Quizz.

Test it now

Question tools

2 follower(s)

Stats

Asked: 9/1/15, 4:10 PM
Seen: 1246 times
Last updated: 9/3/15, 8:51 PM