Odoo 15 "required field is not set" eventhough it is clearly selected

Viewed 27

I have created a video to demonstrate the video: https://vimeo.com/748701130

When I click on save in the event.booth model that is open, I get the error message that event.event has not been selected but it is a required field. This is however not true, as visible in the video. The field is clearly selected.

This is the code for the model: (I am inheriting event.booth)

# -*- coding: utf-8 -*-
from odoo import models, fields, api
from . import prepare_engine as rectanglemaps_engine


class EventBooth(models.Model):
    _inherit = 'event.booth'

    name = fields.Char(string='Name', compute='_compute_name')
    display_name = fields.Char(string="Anzeigename", compute='_compute_display_name', inverse='_inverse_display_name',  store=True)

    # Verbundene Halle
    halle_id = fields.Many2one('rectanglemaps.halle', string='Halle')

    # Allgemein
    start_number = fields.Float(string="Von", default=0, required=True)
    front = fields.Float(string="Front", default=4, required=True)
    end_number = fields.Float(string="Bis", compute='_compute_end_number', inverse='_inverse_end_number', store=True)

    area = fields.Float(string="Fläche", compute='_compute_area', store=True)
    depth = fields.Float(string="Standtiefe", compute='_compute_depth', inverse='_inverse_depth', store=True)

    # Planattribute
    draw = fields.Boolean(string="Einzeichnen", default=True)
    stand_inset = fields.Float(string="Stand Einsatz", default=0)
    walls = fields.Selection([('b', 'Braun'), ('w', 'Weiß')], string="Wände")
    # carpet = fields.Selection([('1', 'orange'), ('2', 'grün'), ('3', 'grau'), ('4', 'blau')], string="Teppich")
    carpet = fields.Many2one('rectanglemaps.carpet', string='Teppich')

    # Planattribute - Wände
    available_walls = [('b', 'Braun'), ('w', 'Weiß')]
    # upper wall
    wall_1_draw = fields.Boolean(string="Obere Wand", compute='_compute_wall_1_draw', inverse='_inverse_wall', store=True)
    wall_1_start = fields.Float(string="Einsatz links")
    wall_1_end = fields.Float(string="Einsatz rechts")
    wall_1_color = fields.Selection(available_walls, string="Wandtyp", default='w')
    # rightmost wall
    wall_2_draw = fields.Boolean(string="Rechte Wand", compute='_compute_wall_2_draw', inverse='_inverse_wall', store=True)
    wall_2_start = fields.Float(string="Einsatz oben")
    wall_2_end = fields.Float(string="Einsatz unten")
    wall_2_color = fields.Selection(available_walls, string="Wandtyp", default='w')
    # lower wall
    wall_3_draw = fields.Boolean(string="Untere Wand", compute='_compute_wall_3_draw', inverse='_inverse_wall', store=True)
    wall_3_start = fields.Float(string="Einsatz links")
    wall_3_end = fields.Float(string="Einsatz rechts")
    wall_3_color = fields.Selection(available_walls, string="Wandtyp", default='w')
    # leftmost wall
    wall_4_draw = fields.Boolean(string="Linke Wand", compute='_compute_wall_4_draw', inverse='_inverse_wall', store=True)
    wall_4_start = fields.Float(string="Einsatz oben")
    wall_4_end = fields.Float(string="Einsatz unten")
    wall_4_color = fields.Selection(available_walls, string="Wandtyp", default='w')

    # Standvorschau
    preview = fields.Image(string="Vorschau")

    @api.depends('halle_id.name', 'start_number', 'front')
    def _compute_name(self):
        for record in self:
            try:
                sn = record.start_number
                if (record.start_number).is_integer():
                    sn = int(record.start_number)

                en = record.start_number + record.front
                if (en).is_integer():
                    en = int(en)

                record.name = record.halle_id.name + ' | ' + str(sn) + ' - ' + str(en)
            except:
                record.name = 'Stand'

    @api.depends('start_number', 'front')
    def _compute_end_number(self):
        for record in self:
            record.end_number = record.start_number + record.front

    def _inverse_end_number(self):
        for record in self:
            record.front = record.end_number - record.start_number

    @api.depends('start_number', 'end_number', 'depth')
    def _compute_area(self):
        for record in self:
            record.area = (record.end_number - record.start_number) * record.depth

    @api.depends('partner_id.name')
    def _compute_display_name(self):
        for record in self:
            record.display_name = record.partner_id.name

    @api.depends('start_number')
    def _compute_depth(self):
        for record in self:
            if record.start_number < 200:
                record.depth = record.halle_id.stand_s
            elif record.start_number < 400:
                record.depth = record.halle_id.stand_e
            elif record.start_number < 600:
                record.depth = record.halle_id.stand_n
            elif record.start_number < 800:
                record.depth = record.halle_id.stand_w



    @api.depends()
    def _inverse_depth(self):
        for record in self:
            pass

    @api.depends()
    def _inverse_display_name(self):
        for record in self:
            pass

    @api.depends('start_number')
    def _compute_wall_1_draw(self):
        for record in self:
            record.wall_1_draw = 200 < record.start_number < 1000

    @api.depends('start_number')
    def _compute_wall_2_draw(self):
        for record in self:
            record.wall_2_draw = record.start_number < 600 or 800 < record.start_number < 1000

    @api.depends('start_number')
    def _compute_wall_3_draw(self):
        for record in self:
            record.wall_3_draw = record.start_number < 400 or 600 < record.start_number < 1000

    @api.depends('start_number')
    def _compute_wall_4_draw(self):
        for record in self:
            record.wall_4_draw = record.start_number < 200 or 400 < record.start_number < 1000

    def _inverse_wall(self):
        for record in self:
            pass


    # used in view
    def action_confirm_stand(self):
        self.state = 'done'

    # used in view
    def action_cancel_stand(self):
        self.state = 'cancelled'


    def action_plan_redraw(self):
        self.draw_preview()

    def draw_preview(self):
        self.preview = rectanglemaps_engine.prepare_engine_stand(self)

    # used in view
    def action_create_offer(self):
        print("Create offer")

    @api.model
    def create(self, values):
        if self.halle_id != False:
            values['event_id'] = self.halle_id.event_id.id
        return super(EventBooth, self).create(values)

    @api.onchange('name', 'start_number', 'end_number', 'depth', 'wall_1_draw', 'wall_1_start', 'wall_1_end', 'wall_2_draw', 'wall_2_start', 'wall_2_end', 'wall_3_draw', 'wall_3_start', 'wall_3_end', 'wall_4_draw', 'wall_4_start', 'wall_4_end')
    def change(self):
        self.draw_preview()

    def action_create_order_rectanglemaps(self):
        action = self.env["ir.actions.actions"]._for_xml_id("rectanglemaps.action_rectanglemaps_create_order")
        ctx = {'default_event_booth_id': self.id,
               'default_event_id': self.event_id.id if self.event_id else False,
               'default_partner_id': self.partner_id.id if self.partner_id else False
               }
        action['context'] = ctx
        return action
1 Answers

You are trying to get a field value (halle_id) in create function before calling supper:

@api.model
def create(self, values):
    if self.halle_id != False:
        values['event_id'] = self.halle_id.event_id.id
    return super(EventBooth, self).create(values)

self is an empty recordset and the field values are not available

halle_id and event_id are of type Many2one and their values will be empty recordsets, self.halle_id != False expression will be evaluated to True and Odoo will set the value of event_id in values to False because the value of the id field of an empty recordset is False then it will raise an error because the required field event_id is not set.

You can call super and then get the halle_id field value:

@api.model
def create(self, values):
    res = super(EventBooth, self).create(values)
    # Now you can use `res.halle_id`
    return res

Or use its value in values as an integer:

self.halle_id.browse(values['halle_id'])

Note that you can use onchange decorator to fill the value of the event_id when the value of halle_id changes

Related