Home > Software engineering >  How to create Odoo records with multilevel dictionaries in Python
How to create Odoo records with multilevel dictionaries in Python

Time:11-11

I am struggling in creating a recursive method to automate record creation in Odoo. I request the WSDL of a SOAP service and process it until I receive the following string:

{'notificaCertificadoRevocado':{
   'input': {
      'SolicitudNotificaRevocado':{
         'optional': False,
         'type': {
            'certificado': {
                'optional': False,
                'type': 'String(value)'
                },
            'codigoAmbiente': {
                'optional': False,
                'type': 'Int(value)'
                }
             }
          }
       }
   }
}

This dictionary has 1 parent parameter "SolicitudNotificaRevocado" and 2 child parameters "certificado" and "codigoAmbiente".

My python method by the moment looks like this:

    def _prepare_parameter_list(self, parameter_dict, recursive_data=False):
        building_data = recursive_data if recursive_data else {}
        parameter_list = []
        for key, value in parameter_dict.items():
            if key != 'optional' and key != 'type':
                # Create parameters
                parameter_name_dict = {
                    'name': key,
                    'description': ' '.join(word.capitalize() for word in camel_case_split(key)),
                }
                characterization_dict = self._prepare_parameter_list(value)
                built_parameter_dict = {**parameter_name_dict, **characterization_dict}
                parameter_list.append((0, 0, built_parameter_dict))
                # TODO: Here the code stops
                return parameter_list
            else:
                if key == 'optional':
                    building_data = {**building_data, **{'optional': value}}
                if key == 'type':
                    if isinstance(value, dict):
                        building_data = {**building_data, **{'parameter_ids': self._prepare_parameter_list(value)}}
                    else:
                        building_data = {**building_data, **{'type': value.split('(')[0]}}
        return building_data

This is working pretty good with only one problem, the data that is being returned has the following form:

[(0, 0, {
   'name': 'SolicitudOperacionesCuis',
   'description': 'Solicitud Operaciones Cuis',
   'optional': False,
   'parameter_ids': [
      (0, 0, {
         'name': 'codigoAmbiente',
         'description': 'Codigo Ambiente',
         'optional': False,
         'type': 'Int'})]
      })
      ]

The problem is that the method after processing one of the child parameters stops because of the "return parameter_list" part. (I have even added a TODO comment in the problem part) I would like to retrieve the following data:

[(0, 0, {
   'name': 'SolicitudOperacionesCuis',
   'description': 'Solicitud Operaciones Cuis',
   'optional': False,
   'parameter_ids': [
      (0, 0, {
         'name': 'certificado',
         'description': 'Certificado',
         'optional': False,
         'type': 'String'})]
      }),
      (0, 0, {
         'name': 'codigoAmbiente',
         'description': 'Codigo Ambiente',
         'optional': False,
         'type': 'Int'})]
      })
       ]

How should I tweak my method to achieve this? Working with recursive methods is hard!

CodePudding user response:

In the end I took a different approach refactoring the method drastically. Because my previous code had an additional problem. If checking the previous desired output:

[(0, 0, {
   'name': 'SolicitudOperacionesCuis',
   'description': 'Solicitud Operaciones Cuis',
   'optional': False,
   'parameter_ids': [
      (0, 0, {
         'name': 'certificado',
         'description': 'Certificado',
         'optional': False,
         'type': 'String'})]
      }),
      (0, 0, {
         'name': 'codigoAmbiente',
         'description': 'Codigo Ambiente',
         'optional': False,
         'type': 'Int'})]
      })
       ]

There is a nested One2many record creation that Odoo does not recognize. Anyway, since I was not able to make the previous code to work, I started creating records individually:

    def _create_parameters(self, process_object, parameter_id=False, parent_parameter_id=False):
        for key, value in process_object.items():
            if key != 'optional' and key != 'type':
                try:
                    soap_parameter = self.env['soap.parameter'].search([
                        '&', '&', '&', '&',
                        ['active', '=', True],
                        ['name', '=', key],
                        ['description', '=', ' '.join(word.capitalize() for word in camel_case_split(key))],
                        ['method_id', '=', self.id],
                        ['parent_id', '=', parent_parameter_id]
                    ], limit=1)[0]
                except IndexError:
                    # Create parameters
                    soap_parameter = self.env['soap.parameter'].create({
                        'name': key,
                        'description': ' '.join(word.capitalize() for word in camel_case_split(key)),
                        'method_id': self.id,
                        'parent_id': parent_parameter_id
                    })
                self._create_parameters(value, soap_parameter, soap_parameter.id)
            if parameter_id:
                if key == 'optional':
                    parameter_id.write({'optional': value})
                if key == 'type':
                    if isinstance(value, dict):
                        self._create_parameters(value, parent_parameter_id=parent_parameter_id)
                    else:
                        value_type = value.split('(')[0]
                        if value_type == 'Int':
                            value_type = 'int'
                        elif value_type == 'String':
                            value_type = 'str'
                        elif value_type == 'Long':
                            value_type = 'float'
                        parameter_id.write({'type': value_type})

This code would search and update or create my parameters.

CodePudding user response:

If the input data is already known and it seems the useful data is the one in the input dictionary, then you don't need the recursion element. Updated a similar function below that outputs your expected output

def _prepare_parameter_list(parameter_dict):
    def _return_data_type(value_type):
        if value_type == 'Int':
            value_type = 'int'
        elif value_type == 'String':
            value_type = 'str'
        elif value_type == 'Long':
            value_type = 'float'
        return value_type

    parent = parameter_dict.get('notificaCertificadoRevocado')
    building_data = []
    if parent and parent.get('input'):
        for key, value in parent['input']:
            vals = {
                'name': key,
                'description': ' '.join(word.capitalize() for word in camel_case_split(key)),
                'optional': value.get('optional'),
            }
            parameter_ids = []
            if value.get('type'):
                for par_key, par_value in value['type']:
                    pams = {
                        'name': par_key,
                        'description': par_key.capitalize(),
                        'optional': par_value.get('optional'),
                        'type': par_value.get('type') and _return_data_type(par_value['type'].split('(')[0]) or False,
                    }
                    parameter_ids.append((0, 0, pams))
            vals.update(parameter_ids=parameter_ids)
            building_data.append((0, 0, vals))
    return building_data
  • Related