Skip to content

Commit

Permalink
add very basic vcard export
Browse files Browse the repository at this point in the history
  • Loading branch information
LordVan committed Jun 1, 2023
1 parent 0968062 commit 0bf92a0
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 0 deletions.
3 changes: 3 additions & 0 deletions rm_extra_data/__init__.py
Expand Up @@ -4,6 +4,9 @@
from . import stock
from . import product
from . import invoice
from . import routes

__all__ = ['register', 'routes']

def register():
Pool.register(
Expand Down
36 changes: 36 additions & 0 deletions rm_extra_data/party.py
Expand Up @@ -77,6 +77,42 @@ def copy(cls, parties, default=None):
default.setdefault('dolibarr_cid', None)
return super().copy(parties, default=default)

def to_vcard(self):
vclines = ['BEGIN:VCARD', 'VERSION:4.0']
if self.legal_name and self.legal_name.strip():
# our internal names sometimes are shortened for convenience so use legal_name
vclines.append(f'FN:{self.legal_name.strip()}')
else:
vclines.append(f'FN:{self.name.strip()}')
for ad in self.addresses:
# TODO: do we want to add subdivision ?
street = ad.street.strip().replace("\n", "\\n") # fstring expression part cannot include backslash
vclines.append(f'ADR:;;{street};{ad.city.strip() if ad.city else ""};{ad.postal_code.strip() if ad.postal_code else ""};{ad.subdivision.name.strip() if ad.subdivision and ad.subdivision.name.strip() else ""};{ad.country.name.strip() if ad.country and ad.country.name else ""}')

This comment has been minimized.

Copy link
@hodeinavarro

hodeinavarro Jun 1, 2023

Hello, I'm here from your post on discuss.

Have you checked the full_address property? It's customisable by the user specifying a format, check the implementation and the doc reference.

This comment has been minimized.

Copy link
@LordVan

LordVan Jun 1, 2023

Author Owner

yes that is an option too, but we still need it in the format for vcards which is detailed in the RFC https://www.rfc-editor.org/rfc/rfc6350.html#section-6.3.1
post officebox; extended address;street;city;region;postalcode;country so i think it is probably not too useful here to match the VCARD standard

This comment has been minimized.

Copy link
@hodeinavarro

hodeinavarro Jun 1, 2023

Ah I see, great 👍🏼

for cm in self.contact_mechanisms:
# phone number types according to RFC6350:
# https://www.rfc-editor.org/rfc/rfc6350.html#section-6.4.1
if cm.type == 'phone':
vclines.append(f'TEL;TYPE=voice:{cm.value}')
elif cm.type == 'mobile':
vclines.append(f'TEL;TYPE=cell:{cm.value}')
elif cm.type == 'fax':
vclines.append(f'TEL;TYPE=fax:{cm.value}')
elif cm.type == 'email':
# types WORK and HOME
# https://www.rfc-editor.org/rfc/rfc6350.html#section-6.4.2
# setting no type since there is no standard way to differenciate between home and work
vclines.append(f'EMAIL:{cm.value}')
elif cm.type == 'website':
pass
elif cm.type in ('skype', 'sip', 'irc', 'jabber'):
vclines.append(f'IMPP;{cm.type}:{cm.value}')
elif cm.type == 'other':
pass
else:
pass
vclines.append('END:VCARD')
return '\n'.join(vclines)


class Replace(metaclass=PoolMeta):
__name__ = 'party.replace'
Expand Down
18 changes: 18 additions & 0 deletions rm_extra_data/routes.py
@@ -0,0 +1,18 @@
from trytond.protocols.wrappers import (
HTTPStatus, Response, abort, with_pool, with_transaction)
from trytond.pool import Pool
from trytond.wsgi import app

def create_carddav():
pool = Pool()
Party = pool.get('party.party')
ret = ''
for p in Party.search([]):
ret += p.to_vcard()
return ret

@app.route('/<database_name>/party/carddav', methods = {'GET'})
@with_pool
@with_transaction()
def vcards(request, pool):
return Response(create_carddav(), content_type='text/vcard')

0 comments on commit 0bf92a0

Please sign in to comment.