0

Hay I am new to Odoo Customizing and Python and wanted to know how I can iterate through a field and take the values out of the field and put them in a new one.

The field I want to iterate through contains multiple email adresses. I want to iterate through these email adress fields, collect the email adresses and store them together in a new field.

For that I need a function.

The field I want to iterate through: My One2many field contains multiple mail adresses which I want to iterate through and collect.


field_contacts_customer_info = fields.One2many(
        'contacts.customer.information', 'another_id', string='Contacts for customer information')

The field I want to store the collected email adresses in:

selected_email = fields.Char(compute='compute_email')

This is my class: I want to collect all the email adresses from the mail_contacts field.

    _name = 'contacts.customer.information'
    _rec_name = 'name_contacts'

    name_contacts = fields.Many2one(
        'res.partner', string="Person", domain = [('is_company', '=', False)])

    mail_contacts = fields.Char(
        related = 'name_contacts.email' ,string="Email")

    another_id = fields.Many2one('res.partner', string="AnotherID")

My Try: This function collects only the last set record of the field_contacts_customer_info field and puts this record in the selected_email field of every company.So it does not work right. It should collect all the mails of the field_contacts_customer_info field for every company seperated and then put them in the selected_mail field of the belonging company.

@api.onchange('field_contacts_customer_info.mail_contacts')
def compute_email(self): 
        list_email = [] 
        for record in self: 
            if record.is_company: 
                for element in record.field_contacts_customer_info: 
                    if element.name_contacts: 
                        list_email.append(element.mail_contacts) 
                    for email in list_email: 
                        self.selected_email = email 

Thanks.

kayalotta
  • 53
  • 9

1 Answers1

0

You need to iterate over self which is a record set and loop over field_contacts_customer_info field to get mail_contacts field values.

@api.depends('field_contacts_customer_info.mail_contacts')
def get_email(self):
    for record in self:
        record.selected_email = ','.join(info.mail_contacts for info in record.field_contacts_customer_info if info.mail_contacts)

Then set the compute attribute to get_email:

selected_email = fields.Char(string="Mail4Info", compute='get_email')

You can check the ORM documentation on how to use the computed fields.

Edit (compute method):

You are setting the value of selected_email to each element of list_email, after the compute_email is executed the value of selected_email will always be the last value of list_email.

The last for loop is executed each time we loop over record.field_contacts_customer_info, it should be at the same level as the second loop.

The list_email is declared before we loop over records (it is not reset in the loop), after the first record, each record will use the email values of previous records.

When record.is_company is evaluated to False, the compute method will not assign a field value, you should see the following error:

ValueError: Compute method failed to assign {record description}.selected_email

It happens because the compute method must assign a field value

Example:

@api.depends('field_contacts_customer_info.mail_contacts')
def compute_email(self):
    for record in self:
        list_email = []
        if record.is_company:
            for element in record.field_contacts_customer_info:
                if element.name_contacts:
                    list_email.append(element.mail_contacts)
            emails = ""
            for email in list_email:
                emails += email + " "
            record.selected_email = emails
        else:
            record.selected_email = ""

You can change the list_email type to a string and avoid looping again to get the field value:

Example:

@api.depends('field_contacts_customer_info.mail_contacts')
def compute_email(self):
    for record in self:
        list_email = ""
        if record.is_company:
            for element in record.field_contacts_customer_info:
                if element.name_contacts:
                    list_email += element.mail_contacts
        record.selected_email = list_email
Kenly
  • 24,317
  • 7
  • 44
  • 60
  • thank you! Maybe you can proof if I understood it right: The '@api.depends' keeps an eye on the 'field_contacts_customer_info.mail_contacts' - field and is triggered whenever ist changes. When '@api.depends' is triggered the function get_email is called which has the parameter self, that represents an object in my class. for every record so for every email adress in this case we add the record to the selected_email - field by saying record.selected_email and after that I am a little bit lost the comma seperates the records. Maybe you can explain the part after that so that I can understand. – kayalotta Dec 02 '21 at 18:48
  • Yes and `self` can represent multiple records. I used the comma just to separate the email addresses. The `get_email` method must assign the computed value to the field. – Kenly Dec 03 '21 at 19:28
  • Thank you! I got one question left. You used "info." where does that come from and what does it do or represent ? – kayalotta Dec 09 '21 at 10:17
  • It represents a `contacts.customer.information` record. I used a [generator comprehension](https://stackoverflow.com/questions/364802/how-exactly-does-a-generator-comprehension-work) and iterated over `field_contacts_customer_info` using `info` variable name – Kenly Dec 09 '21 at 10:37
  • Does this answer help you? – Kenly Dec 16 '21 at 18:40
  • Yes you helped me at that time and it worked finde on my machine. When I tried putting my code on the live machine I got an error with that code: "TypeError: sequence item 0: expected str instance, bool found" Do you have an idea why this appears ? For me the compute attribute is confusing, you think it could be because of this attribute ? is there another way that I can add the "join-string" into the selected_email field ? Thanks – kayalotta Jan 06 '22 at 10:58
  • This happens because at least one `mail_contacts` field is not defined, you can resolve the error by adding a condition in the join call. I updated my answer – Kenly Jan 06 '22 at 11:22
  • By not defined you mean that there is no content in it or rather that there is no email address in at least one one the mail_contacts fields ? – kayalotta Jan 06 '22 at 12:22
  • I mean the value is not set (Defaults to ``False``) – Kenly Jan 06 '22 at 12:40
  • so when we do not give the if condition the mail_contacts field has the value false which is why we get the error "bool found". And by giving the if condition we are saying that the join should only happen when mail_contacts has a value ? – kayalotta Jan 06 '22 at 12:55
  • Yes, we use the if condition to filter out the boolean `mail_contacts` values – Kenly Jan 06 '22 at 13:01
  • hay, today I tried out your idea on the live machine but it did not work. I can enter the view without getting an error now, but the mail adresses are not added into the selected_email field. – kayalotta Jan 10 '22 at 07:46
  • Did you use the `store` attribute? – Kenly Jan 12 '22 at 23:13
  • No. I try avoiding the join statement now, because I think it it does not work with the databank of the live machine for me. I updated my question and showed my new code. Maybe you can help. – kayalotta Jan 13 '22 at 10:02
  • It will save only the last value in the list, check my edit – Kenly Jan 13 '22 at 11:03
  • I just noticed that you changed the decorator to `onchange` but you used dotted field names which are not supported. You can check the waring at [odoo.api.onchange(*args)](https://www.odoo.com/documentation/15.0/developer/reference/backend/orm.html#odoo.api.onchange). ``@onchange`` only supports simple field names, dotted names (fields of relational fields ``e.g. partner_id.tz``) are not supported and ``will be ignored`` – Kenly Jan 13 '22 at 11:09
  • @kayalotta Does this answer your question? – Kenly Jan 13 '22 at 16:21