Mòdul escola — Alumnes, Mòduls i Professors (port 8070)

Aquesta guia crea un mòdul complet amb menús i permisos. Inclou la solució definitiva del Many2one de Professor perquè es mostri el nom i no “escola.professor,1”.

0) Punt de partida

1) Crear el mòdul “escola”

odoo scaffold escola ~/odoo-dev/custom-addons

Si no tens scaffold, crea manualment la carpeta i fitxers tal com mostrem més avall.

2) Estructura i manifest

Edita ~/odoo-dev/custom-addons/escola/__manifest__.py amb aquest contingut (ordre de fitxers clau: accions abans dels menús).

{
    "name": "Escola",
    "version": "17.0.1.0.0",
    "category": "Education",
    "summary": "Gestió d'alumnes, mòduls i professors",
    "author": "Tu",
    "depends": ["base"],
    "data": [
      "security/ir.model.access.csv",

      "views/escola_actions.xml",   # ACCIONS primer
      "views/escola_menus.xml",     # MENÚS després

      "views/alumne_views.xml",
      "views/modul_views.xml",
      "views/professor_views.xml"
    ],
    "installable": True,
    "application": True
}
Amb això evitem l’error vist anteriorment: External ID not found: escola.action_alumnes.

3) Models

Crea els fitxers a ~/odoo-dev/custom-addons/escola/models.

3.1 __init__.py

from . import professor
from . import modul
from . import alumne

3.2 professor.py — (solució Many2one: nom complet)

from odoo import models, fields, api

class EscolaProfessor(models.Model):
    _name = "escola.professor"
    _description = "Professor"
    _rec_name = "name"  # camp que es mostra als Many2one

    # nom i cognoms, i un 'name' calculat per mostrar-se arreu
    first_name = fields.Char(string="Nom", required=True)
    last_name  = fields.Char(string="Cognoms", required=True)

    name = fields.Char(string="Nom complet", compute="_compute_name", store=True)
    email = fields.Char()

    @api.depends('first_name', 'last_name')
    def _compute_name(self):
        for rec in self:
            parts = [p for p in [rec.first_name, rec.last_name] if p]
            rec.name = " ".join(parts) if parts else False
Fix Many2one: definim _rec_name = "name" i calculem name amb nom+cognoms. Ara els Many2one mostraran el nom del professor, no “escola.professor,1”.

3.3 modul.py

from odoo import models, fields

class EscolaModul(models.Model):
    _name = "escola.modul"
    _description = "Mòdul formatiu"

    name = fields.Char(string="Nom del mòdul", required=True)
    code = fields.Char(string="Codi")

    professor_id = fields.Many2one(
        "escola.professor",
        string="Professor",
        ondelete="set null",
    )

    alumne_ids = fields.Many2many(
        "escola.alumne",
        "escola_alumne_modul_rel",
        "modul_id", "alumne_id",
        string="Alumnes"
    )

3.4 alumne.py

from odoo import models, fields

class EscolaAlumne(models.Model):
    _name = "escola.alumne"
    _description = "Alumne"

    name = fields.Char(string="Nom i cognoms", required=True)
    email = fields.Char()

    modul_ids = fields.Many2many(
        "escola.modul",
        "escola_alumne_modul_rel",
        "alumne_id", "modul_id",
        string="Mòduls"
    )

4) Vistes

Crea els fitxers a ~/odoo-dev/custom-addons/escola/views.

4.1 professor_views.xml

<?xml version="1.0" encoding="utf-8"?>
<odoo>
  <record id="view_professor_tree" model="ir.ui.view">
    <field name="name">escola.professor.tree</field>
    <field name="model">escola.professor</field>
    <field name="arch" type="xml">
      <tree>
        <field name="name"/>
        <field name="first_name"/>
        <field name="last_name"/>
        <field name="email"/>
      </tree>
    </field>
  </record>

  <record id="view_professor_form" model="ir.ui.view">
    <field name="name">escola.professor.form</field>
    <field name="model">escola.professor</field>
    <field name="arch" type="xml">
      <form>
        <sheet>
          <group>
            <field name="first_name"/>
            <field name="last_name"/>
            <field name="name" readonly="1"/>
            <field name="email"/>
          </group>
        </sheet>
      </form>
    </field>
  </record>
</odoo>

4.2 modul_views.xml

<odoo>
  <record id="view_modul_tree" model="ir.ui.view">
    <field name="name">escola.modul.tree</field>
    <field name="model">escola.modul</field>
    <field name="arch" type="xml">
      <tree>
        <field name="name"/>
        <field name="code"/>
        <field name="professor_id"/>
      </tree>
    </field>
  </record>

  <record id="view_modul_form" model="ir.ui.view">
    <field name="name">escola.modul.form</field>
    <field name="model">escola.modul</field>
    <field name="arch" type="xml">
      <form>
        <sheet>
          <group>
            <field name="name"/>
            <field name="code"/>
            <field name="professor_id"/>
            <field name="alumne_ids" widget="many2many_tags"/>
          </group>
        </sheet>
      </form>
    </field>
  </record>
</odoo>

4.3 alumne_views.xml

<odoo>
  <record id="view_alumne_tree" model="ir.ui.view">
    <field name="name">escola.alumne.tree</field>
    <field name="model">escola.alumne</field>
    <field name="arch" type="xml">
      <tree>
        <field name="name"/>
        <field name="email"/>
        <field name="modul_ids" widget="many2many_tags"/>
      </tree>
    </field>
  </record>

  <record id="view_alumne_form" model="ir.ui.view">
    <field name="name">escola.alumne.form</field>
    <field name="model">escola.alumne</field>
    <field name="arch" type="xml">
      <form>
        <sheet>
          <group>
            <field name="name"/>
            <field name="email"/>
            <field name="modul_ids"/>
          </group>
        </sheet>
      </form>
    </field>
  </record>
</odoo>

5) Accions i menús

5.1 escola_actions.xml

<odoo>
  <record id="action_alumnes" model="ir.actions.act_window">
    <field name="name">Alumnes</field>
    <field name="res_model">escola.alumne</field>
    <field name="view_mode">tree,form</field>
  </record>

  <record id="action_moduls" model="ir.actions.act_window">
    <field name="name">Mòduls</field>
    <field name="res_model">escola.modul</field>
    <field name="view_mode">tree,form</field>
  </record>

  <record id="action_professors" model="ir.actions.act_window">
    <field name="name">Professors</field>
    <field name="res_model">escola.professor</field>
    <field name="view_mode">tree,form</field>
  </record>
</odoo>

5.2 escola_menus.xml

<odoo>
  <menuitem id="menu_escola_root" name="Escola"/>

  <menuitem id="menu_escola_alumnes" name="Alumnes"
            parent="menu_escola_root" action="action_alumnes"/>

  <menuitem id="menu_escola_moduls" name="Mòduls"
            parent="menu_escola_root" action="action_moduls"/>

  <menuitem id="menu_escola_professors" name="Professors"
            parent="menu_escola_root" action="action_professors"/>
</odoo>
Recorda: accions primer, menús després. Així evitem el External ID not found.

6) Permisos

Crea ~/odoo-dev/custom-addons/escola/security/ir.model.access.csv:

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_escola_alumne,access.escola.alumne,model_escola_alumne,base.group_user,1,1,1,1
access_escola_modul,access.escola.modul,model_escola_modul,base.group_user,1,1,1,1
access_escola_professor,access.escola.professor,model_escola_professor,base.group_user,1,1,1,1

7) Instal·lació i proves

  1. Reinicia/arrenca el servidor de dev:
    odoo -c ~/.odoorc.dev -d dev_escola --http-port=8070 --dev=all
  2. A Apps: Update Apps List, busca “Escola” i Install. (o bé per consola: odoo -c ~/.odoorc.dev -d dev_escola -u escola --stop-after-init)
  3. Ves a Escola → Professors, crea’n un (Nom + Cognoms). Ves a Escola → Mòduls, crea un mòdul i assigna-hi el professor → ara el Many2one mostra el nom complet.
  4. Ves a Escola → Alumnes, crea un alumne i afegeix-li mòduls. A la llista d’alumnes veuràs els mòduls com a tags.

8) Errors típics i solucions (recap)

“escola.professor,1” a Many2one
Defineix un camp de nom (ex. name) i usa _rec_name = "name". En aquest mòdul calculem name = first_name + last_name.
External ID not found: escola.action_alumnes
Carrega escola_actions.xml abans d’escola_menus.xml al manifest i comprova els IDs.
No surt “Update Apps List”
Activa el Developer mode a Settings.
No apareix el mòdul
Confirma addons_path i repeteix Update Apps List. El nostre ~/.odoorc.dev ja inclou ~/odoo-dev/custom-addons.

9) Cicle de desenvolupament

# Actualitzar només el mòdul 'escola' i sortir:
odoo -c ~/.odoorc.dev -d dev_escola -u escola --stop-after-init

# Tornar a deixar-lo corrent al 8070:
odoo -c ~/.odoorc.dev -d dev_escola --http-port=8070 --dev=all

Què ve a la Pàg. 3?