Add parties, addresses, contacts with proteus

Hello Everybody,

I hope you’re fine on your side.

I’m using proteus for adding parties.

I’d like to know :

  • How is it possible to find a field through the client ? Example : I want to know how to check Invoice or delivery on a party address
  • How can i iterate address on a party, or find it ? I can only iterate party.addresses ? (Like in the proteus documentation)
  • Is it possible to link a contact to an address, I analyze the migration between a proprietary ERP and Tryton. In the ERP, the contact are linked to a delivery address or to an invoice address. I only saw the possibility to link a contact to a party not to an address. There is a possibility to do this or I need to type the different contact like delivery contact or invoice contact.

Sorry for the level of the different question and Thank you for your help.

Best regards
Johan

Address = Model.get('party.address')
address = Address.find(['delivery','=',True])

You can iterate any record

for i in address:
    print(i.city)

In 6.6 this is a new feature. Next to the contact you can select the address.

Hello dotbit, thank you for your reply, i will check it on a demo.

Re,

I try to add Addresses it’s ok now.

A new question, it’s not possible to delete all adresses of a party ?

party, = Party.find([('code', '=', rowCustomer['Code'])])
while party.addresses:
    party.addresses.pop()

I got the error bellow :

Traceback (most recent call last):
  File "/mnt/d/Developpement/docker/dockermssqldph/source/GRCToTryton.py", line 76, in <module>
    party.save()
  File "/mnt/d/Developpement/docker/dockermssqldph/source/venv/lib/python3.10/site-packages/proteus/__init__.py", line 102, in newfunc
    return self.func(owner, [instance], *args, **kwargs)
  File "/mnt/d/Developpement/docker/dockermssqldph/source/venv/lib/python3.10/site-packages/proteus/__init__.py", line 866, in save
    proxy.write(*values)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1122, in __call__
    return self.__send(self.__name, args)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1464, in __request
    response = self.__transport.request(
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1166, in request
    return self.single_request(host, handler, request_body, verbose)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1182, in single_request
    return self.parse_response(resp)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1354, in parse_response
    return u.close()
  File "/usr/lib/python3.10/xmlrpc/client.py", line 668, in close
    raise Fault(**self._stack[0])
xmlrpc.client.Fault: <Fault 1: "Vous ne pouvez pas changer le tiers de l'adresse «\xa0.......\xa0». - ">

When I search in the party module, I find this code :

@classmethod
    def write(cls, *args):
        actions = iter(args)
        for addresses, values in zip(actions, actions):
            if 'party' in values:
                for address in addresses:
                    if address.party.id != values['party']:
                        raise AccessError(
                            gettext('party.msg_address_change_party',
                                address=address.rec_name))
        super(Address, cls).write(*args)

I’ve debug the different Id (party and party.id in address) and they are identical. I don’t understand this error.

A workaround is to get all adresses of a party with find and to delete each address, like this :

address = Address.find([('party', '=', rowCustomer['Code'])])
for ad in address:
    ad.delete()

I’ll try to add a contact on an address now.

Thank you
Johan

Party = Model.get('party.party')
Address = Model.get('party.address')

party, = Party.find([('code', '=', rowCustomer['Code'])])
Address.delete(party.addresses)

Hi David, thank you for your reply. I’ll test it tomorrow.

I abuse … do you have any example for add an address on a contact through proteus ?

Thank you in advance

You can go into Administration / Models in order to see what fields each model has.

You need to have the address object, then the contact object.
Then you can do this: contact.address = address

Hello Dimitrios,

Yes i find it yesterday, I can check the model to find the different field I need. Thank You.
Yesterday, I tried also contact.address = address but it throw me an exception :

Traceback (most recent call last):
  File "/mnt/d/Developpement/docker/dockermssqldph/source/GRCToTryton.py", line 78, in <module>
    party.save()
  File "/mnt/d/Developpement/docker/dockermssqldph/source/venv/lib/python3.10/site-packages/proteus/__init__.py", line 102, in newfunc
    return self.func(owner, [instance], *args, **kwargs)
  File "/mnt/d/Developpement/docker/dockermssqldph/source/venv/lib/python3.10/site-packages/proteus/__init__.py", line 866, in save
    proxy.write(*values)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1122, in __call__
    return self.__send(self.__name, args)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1464, in __request
    response = self.__transport.request(
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1166, in request
    return self.single_request(host, handler, request_body, verbose)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1182, in single_request
    return self.parse_response(resp)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1354, in parse_response
    return u.close()
  File "/usr/lib/python3.10/xmlrpc/client.py", line 668, in close
    raise Fault(**self._stack[0])
xmlrpc.client.Fault: <Fault 1: "La valeur «\xa0-1\xa0» du champ «\xa0Adresse\xa0» sur «\xa0Moyen de contact\xa0» n'existe pas. - ">

I think I must save my party and my address before adding address on the contact.

Today I instanciante a party, I add a new address on this party, I add a new contact on this party. I get both an adress variable with the new method : address = party.adresses.new(postal_code=‘XXXXX’) and contact = party.contact_mechanisms.new(type=‘phone’, value=‘+33XXXXX’).
I add this address on contact.address.

I will change my code for save both party and address, get the party, iterate on addresses and add contact for each.

Thank you for your help.
Johan

Yes, save first, then assign. It is the same in the gtk client, you can not assign the address to the contact mechanism if the address is not already saved.

party.contact_mechanisms[0].address = party.addresses[0]
party.save()

This works for me.

You can also try code in an interactive python interpreter, that way you can test things much faster and instantly see what works and what does not.

… or use the trytond-console.

Indeed it’s another way to import data.

But beware that in this case it’s not a proteus session but it’s just like if you were “inside” trytond.
So the API is different.

Hello all,

Thank you, i can add contact to an address now :slight_smile:
I’ll optimise my migration script.
I think last question, how i can catch properly exception on party.save() ?
Example : bad format for a telephone number

Thank you
Johan

I also had the problem with bad phone number formats on migration, and I did not want to correct them all before the migration, but later.

I uninstalled python module “phonenumbers” within the tryton server environment,

pip uninstall phonenumbers

did the migration, and then reinstalled

pip install phonenumbers

So I could do the migration and then correct the data step by step later.

You can catch the exception with:

    try:
        phonenumber = phonenumbers.parse(mechanism.value)
    except NumberParseException:

and also phonenumbers.is_valid_number(phonenumber)

If it’s not a valid one, we like to set the mechanism to other instead of using phone, so latter it can be corrected.

1 Like

Indeed this is a great solution, thanks, I will do so in the future.