25. Desarrollando con Odoo (20). Recapitulaciones del capítulo 8 (Bussines logic).

1. Disparar reglas de usuario ( 8.274) 

  1. Reglas de validación @api.constrains (fields)
  2. Cálculos automáticos @api.depends (fields)
  3. Valores por defecto @api.model

2. Añadir registros ( 8.283) 

Hay que añadir un fichero xml en la carpeta "data" indicando el modelo, un id y lios campos a añadir

<odoo noupdate="1">
  <record id="stage_new" model="library.checkout.stage">
      <field name="name">Draft</field>
      <field name="sequence">10</field>
      <field name="state">new</field>
  </record>
  <record ...></record>
</odoo>

y definir en el __manifest__.py este fichero en el apartado "data"

  "data": [
    "security/ir.model.access.csv",
    "views/library_menu.xml",
    "data/library_checkout_stage.xml",
  ],

3. Métodos que soportan la interfaz de usuario (8.286)????

  1. name_get()
  2. name_search()
  3. name_create()
  4. default_get()
  5. fields_get()
  6. fields_view_get()

4. Métodos para dar alta /modificaciones/bajas  de registros (8.288)

  1. <Model>.create (values)
  2. <Recordset>.write(values)
  3. <Recordset>.unlink()

5. Métodos ORM para iomportar o exportar datos(8.292)

  1. load([fields],  [data])
  2. export_data([fields])

6. onchange (8.292 (Un poco oscuro?))

Se puede definir de dos maneras. La segunda es un complemento a la primera y se aconseja usarla.:
  1. decorador @api.onchange(fields) sobre la función ,  que se llama asíncronamente desde el cliente 
  2. Usando @api.depends(fields) sobre la fucjnión y  además el atributo del campo compute='función'

7. message y activity(8.297?????)

messaging: Es añadido por mail.thread. Crea un widget "mail_thread" llamado "Chatter". Permite hacer una bitácora de notas o enviar mensajes a otros usuarios
activity: Es añadido por mail.activity.mixin.  Es un widget "mail_activity" para programar actividades y ver el histórico de dichas actividades 
¿followers?:  Es añadido por mail.thread ?? y tiene un widget llamado mail_followers. Los followers pueden ser "partners" (personas o empresas) o canales (listas de subscripción)

Veamos que hay que hacer.
  1. Indicarlo en el __manifest__.py     "depends":["library_member","mail"],
  2. Indicarlo en el modelo    _inherit = ["mail.thread", "mail.activity.mixin"]
  3. Añadir a la vista los widgets mail_followers, mail_activity y mail_thread
         ......
        </sheet>

        <div class="oe_chatter">
          <field name="message_follower_ids" widget="mail_followers" />
          <field name="activity_ids" widget="mail_activity"/>
          <field name="message_ids" widget="mail_thread" />
        </div>
     </form>
   </field>
  </record>
</odoo>

No aparece donde se poone este código fuente ?????????
  1. Enviar mensaje: self.message_post()
  2. Añadir seguidores: message_subscribe(partners) o message_subscribe_users(users)

8. Wizard

El modelo soportado es models.TransientModel
Se crea en la carpeta "wizard"
Se indica en __init__.py   de la carpeta principal del módulo    from . import wizard
Se indica en  __init__.py de la carpeta "wizard"     from . import checkout_mass_message
Crear en la carpeta wizard, el modelo en checkout_mass_message.py 

from odoo import api, exceptions, fields, models
class CheckoutMassMessage(models.TransientModel):
    _name = "library.checkout.massmessage"
    _description = "Send Message to Borrowers"
    checkout_ids = fields.Many2many(
        "library.checkout",
        string="Checkouts",
    )
    message_subject = fields.Char()
    message_body = fields.Html()

Se definirá la seguridad en security/ir.model.csv

Se  crearáen en la carpeta wizard checkout_mass_message_wizard_view.xml con la particularidad que la sección footer guardará los botones y que se añadirá el botón cancel 

<odoo>
  <record id="view_form_checkout_message" model="ir.ui.view">
    <field name="name">Library Checkout Mass Message Wizard</field>
    <field name="model">library.checkout.massmessage</field>
    <field name="arch" type="xml">

      <form>
        <group>
          <field name="message_subject" />
          <field name="message_body" />
          <field name="checkout_ids" />
        </group>
        <footer>
          <button type="object"
            name="button_send"
            string="Send Messages" />
          <button special="cancel" 
            string="Cancel" 
            class="btn-secondary" />
        </footer>
      </form>

    </field>
  </record>
</odoo>

Pero en este mismo fichero, antes de </odoo> hay que incluir la action para abrir el wizard. esta action que es del tipo ir.actions.act_window queda disponible el el menú Action del modelo al que hace referecnioa en binding_model_id

  <record id="action_checkout_message"
          model="ir.actions.act_window">
    <field name="name">Send Messages</field>
    <field name="res_model">library.checkout.massmessage</field>
    <field name="view_mode">form</field>
    <field name="binding_model_id"
           ref="model_library_checkout" />
    <field name="binding_view_types">form,list</field>
    <field name="target">new</field>
  </record>

Hay que añadir la referencia de la vista en el "data" del __manifest__.py.

8.1 Obtener los registros seleccionados en la pantalla que desencadena la acción del wizard


Como vimos en el punto 3 hay una función que es defaul_get([fields]) que es una funcion ORM que se encarga de devolver los valores por defecto de un NUEVOregistro. Lo que hacemos es extender dicha función teniendo en cuenta los siguientes valores almacenados en el "context" que han sido proporcionados por el form donde se solicitó el Action
  1. active_model que es el nombre del modelo.
  2. active_id que es el primer id del grupo de registros seleccionados.
  3. active_ids que contiene todos los ids de los registros seleccionados.
  4. active_domain si la acción es desencadenada desde una vista tipo form.
Parece ser que cuando extendemos la fución default_get, hay que devolver un diccionario con los valores por defecto en este caso lo llamaremos defaults_dict. 
Aquí lo que hacemos es asignar los active_ids del contexto al campo checkout_ids del modelo del wizard, y de paso los metemos en el defaults_dict

Para ello añadimos este código en  checkout_mass_message.py 

    @api.model
    def default_get(self, field_names):
        defaults_dict = super().default_get(field_names)
        # Add values to the defaults_dict here
        checkout_ids = self.env.context["active_ids"]
        defaults_dict["checkout_ids"] = [(6, 0, checkout_ids)]
        return defaults_dict

Ahora falta definir la lógica a desencadenar cuando se apriete el botón "Send Message" en el mismo fichero:

    def button_send(self):
        self.ensure_one()
        if not self.checkout_ids:
            raise exceptions.UserError(
                "No Checkouts were selected."
            )
        if not self.message_body:
            raise exceptions.UserError(
                "A message body is required"
            )
        for checkout in self.checkout_ids:
            checkout.message_post(
                body=self.message_body,
                subject=self.message_subject,
                subtype_xmlid='mail.mt_comment',
            )
            _logger.debug(
                "Message on %d to followers: %s",
                checkout.id,
                checkout.message_follower_ids,
            )

        _logger.info(
            "Posted %d messages to the Checkouts: %s",
            len(self.checkout_ids),
            str(self.checkout_ids),
        )
        return True

Hay que añadir en este mismo fichero:

from odoo import exceptions

Para que reconozca las excepciones.






Comentarios

Entradas populares de este blog

20. Desarrollando con Odoo (15). Permisos y grupos. Crear usuarios de la aplicación. Restringir permisos a usuarios

2. El Modo desarrollador

8. Desarrollando con Odoo (6). Herencia de clase en modelos. Herencia de vistas. Operaciones numeradas en Odoo ??