From 2c603520696168ad21043a9e723c00808646fe2b Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 16 Nov 2024 15:31:05 +0100 Subject: [PATCH 01/32] idoklad start --- rowers/views/paymentviews.py | 4 ++++ rowsandall_app/settings.py | 8 ++++++++ rowsandall_app/urls.py | 1 + 3 files changed, 13 insertions(+) diff --git a/rowers/views/paymentviews.py b/rowers/views/paymentviews.py index f42b476e..904e0487 100644 --- a/rowers/views/paymentviews.py +++ b/rowers/views/paymentviews.py @@ -8,6 +8,10 @@ from django.core.mail import EmailMessage from rowers import credits +def process_idokladcallback(request): + dologging('idoklad.log',' /rowers/idokladcallback/') + + return HttpResponse('') @csrf_exempt def braintree_webhook_view(request): diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py index 8c1d4255..e3fe4e50 100644 --- a/rowsandall_app/settings.py +++ b/rowsandall_app/settings.py @@ -597,6 +597,14 @@ try: except KeyError: # pragma: no cover FAKTUROID_SLUG = '' +try: + IDOKLAD_CLIENT_ID = CFG['idoklad_client_id'] + IDOKLAD_CLIENT_SECRET = CFG['idoklad_client_secret'] +except KeyError: # pragma: no cover + IDOKLAD_CLIENT_ID = '' + IDOKLAD_CLIENT_SECRET = '' + + # ID obfuscation try: OPAQUE_SECRET_KEY = CFG['opaque_secret_key'] diff --git a/rowsandall_app/urls.py b/rowsandall_app/urls.py index 76c518fd..caf20824 100644 --- a/rowsandall_app/urls.py +++ b/rowsandall_app/urls.py @@ -93,6 +93,7 @@ urlpatterns += [ re_path(r'^tp\_callback', rowersviews.rower_process_tpcallback), re_path(r'^rp3\_callback', rowersviews.rower_process_rp3callback), re_path(r'^twitter\_callback', rowersviews.rower_process_twittercallback), + re_path(r'^idoklad\_callback', rowersviews.process_idokladcallback), re_path(r'^i18n/', include('django.conf.urls.i18n')), re_path(r'^tz_detect/', include('tz_detect.urls')), re_path(r'^logo/', logoview), From 1204d7dc15006ddc21391be62bfd533c0118b63c Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 16 Nov 2024 15:40:12 +0100 Subject: [PATCH 02/32] building idoklad --- rowers/models.py | 11 +++++++++++ rowers/views/paymentviews.py | 24 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/rowers/models.py b/rowers/models.py index 5ddc51dc..30cbfc78 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -5365,3 +5365,14 @@ class ForceCurveAnalysis(models.Model): date = self.date) return s + +class iDokladToken(models.Model): + access_token = models.CharField(max_length=512) + refresh_token = models.CharField(max_length=512) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + expires_in = models.IntegerField() # Store token expiry duration in seconds + + def __str__(self): + return f"iDoklad Token updated at {self.updated_at}" + diff --git a/rowers/views/paymentviews.py b/rowers/views/paymentviews.py index 904e0487..6efb02d8 100644 --- a/rowers/views/paymentviews.py +++ b/rowers/views/paymentviews.py @@ -8,8 +8,32 @@ from django.core.mail import EmailMessage from rowers import credits +@login_required() +def rower_idoklad_auth(request): + state=str(uuid4()) + + params = { + "client_id":IDOKLAD_CLIENT_ID, + "response_type": "code", + "redirect_uri": IDOKLAD_REDIRECT_URI, + "scope": "idoklad_api offline_access", + } + + url = "https://identity.idoklad.cz/server/connect/authorize?"+urllib.parse.urlencode(params) + + return HttpResponseRedirect(url) + def process_idokladcallback(request): dologging('idoklad.log',' /rowers/idokladcallback/') + + try: + code = request.GET['code'] + except KeyError: + error = request.GET['error'] + messages.error(request,error) + return HttpResponseRedirect(reverse('workouts_view')) + + return HttpResponse('') From 6a759b637f40401ff23bc95f97c12a532db9ffe6 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 16 Nov 2024 16:11:10 +0100 Subject: [PATCH 03/32] retrieving tokens works --- rowers/templates/rower_exportsettings.html | 4 ++ rowers/urls.py | 1 + rowers/views/paymentviews.py | 45 ++++++++++++++++++++-- rowers/views/statements.py | 3 +- rowsandall_app/settings.py | 4 ++ 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/rowers/templates/rower_exportsettings.html b/rowers/templates/rower_exportsettings.html index a62ad6a2..5d1180f8 100644 --- a/rowers/templates/rower_exportsettings.html +++ b/rowers/templates/rower_exportsettings.html @@ -89,6 +89,10 @@

connect with Rojabo

+{% if user.is_staff %} +

iDoklad authorize

+{% endif %} + {% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index 18b28d66..5691b5c3 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -745,6 +745,7 @@ urlpatterns = [ views.rower_prefs_view, name='rower_prefs_view'), re_path(r'^me/prefs/user/(?P\d+)/$', views.rower_simpleprefs_view, name='rower_simpleprefs_view'), + re_path(r'^me/idokladauthorize/$', views.rower_idoklad_authorize, name='rower_idoklad_authorize'), re_path(r'^me/rojaboauthorize/$', views.rower_rojabo_authorize, name='rower_rojabo_authorize'), re_path(r'^me/polarauthorize/$', views.rower_polar_authorize, diff --git a/rowers/views/paymentviews.py b/rowers/views/paymentviews.py index 6efb02d8..f69942b0 100644 --- a/rowers/views/paymentviews.py +++ b/rowers/views/paymentviews.py @@ -9,7 +9,7 @@ from django.core.mail import EmailMessage from rowers import credits @login_required() -def rower_idoklad_auth(request): +def rower_idoklad_authorize(request): state=str(uuid4()) params = { @@ -23,6 +23,7 @@ def rower_idoklad_auth(request): return HttpResponseRedirect(url) +@login_required() def process_idokladcallback(request): dologging('idoklad.log',' /rowers/idokladcallback/') @@ -33,9 +34,45 @@ def process_idokladcallback(request): messages.error(request,error) return HttpResponseRedirect(reverse('workouts_view')) - - - return HttpResponse('') + post_data = { + 'grant_type': "authorization_code", + 'client_id': IDOKLAD_CLIENT_ID, + 'client_secret': IDOKLAD_CLIENT_SECRET, + 'scope': 'idoklad_api offline_access', + 'code': code, + 'redirect_uri': IDOKLAD_REDIRECT_URI, + } + + headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + } + + base_url = 'https://identity.idoklad.cz/server/connect/token' + + response = requests.post(base_url, data=post_data, headers=headers) + + if response.status_code == 200: + result = response.json() + try: + t = iDokladToken.objects.get(id=1) + t.acces_token = result['access_token'], + t.refresh_token = result['refresh_token'] + t.expires_in = result['expires_in'] + t.save() + except iDokladToken.DoesNotExist: + t = iDokladToken( + access_token = result['access_token'], + refresh_token = result['refresh_token'], + expires_in = result['expires_in'], + ) + t.save() + messages.info(request,"Token refreshed and stored") + else: + messages.error(request,"Error") + + url = reverse('rower_exportsettings_view') + + return HttpResponseRedirect(url) @csrf_exempt def braintree_webhook_view(request): diff --git a/rowers/views/statements.py b/rowers/views/statements.py index d134013d..d4b675f0 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -178,7 +178,7 @@ from rowers.models import ( RowerPowerForm, RowerHRZonesForm, SimpleRowerPowerFo IndoorVirtualRaceForm, PlannedSessionCommentForm, Alert, Condition, StaticChartRowerForm, FollowerForm, VirtualRaceAthleteForm, InstantPlanForm, DataRowerForm, - StepEditorForm, ) + StepEditorForm, iDokladToken ) from rowers.models import ( FavoriteForm, BaseFavoriteFormSet, SiteAnnouncement, BasePlannedSessionFormSet, get_course_timezone, BaseConditionFormSet, @@ -225,6 +225,7 @@ from rowsandall_app.settings import ( RECAPTCHA_SITE_KEY, RECAPTCHA_SITE_SECRET, NK_REDIRECT_URI, NK_CLIENT_ID, NK_CLIENT_SECRET, ROJABO_REDIRECT_URI, ROJABO_CLIENT_ID, ROJABO_CLIENT_SECRET, + IDOKLAD_REDIRECT_URI, IDOKLAD_CLIENT_ID, IDOKLAD_CLIENT_SECRET, ) from django.contrib import messages diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py index e3fe4e50..7cbfe5dc 100644 --- a/rowsandall_app/settings.py +++ b/rowsandall_app/settings.py @@ -97,6 +97,8 @@ AUTHENTICATION_BACKENDS = ( #'rules.permissions.ObjectPermissionBackend', ) +CSRF_TRUSTED_ORIGINS = ['https://rowsandall.com', 'https://www.rowsandall.com', 'http://localhost', 'https://dunav.ngrok.io'] + MIDDLEWARE = [ 'django.middleware.common.CommonMiddleware', 'django.middleware.common.BrokenLinkEmailsMiddleware', @@ -600,9 +602,11 @@ except KeyError: # pragma: no cover try: IDOKLAD_CLIENT_ID = CFG['idoklad_client_id'] IDOKLAD_CLIENT_SECRET = CFG['idoklad_client_secret'] + IDOKLAD_REDIRECT_URI = CFG['idoklad_redirect_uri'] except KeyError: # pragma: no cover IDOKLAD_CLIENT_ID = '' IDOKLAD_CLIENT_SECRET = '' + IDOKLAD_REDIRECT_URI = '' # ID obfuscation From e5effd556781be279ff63915fcdd5e4759ad456d Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 16 Nov 2024 16:35:37 +0100 Subject: [PATCH 04/32] some more work --- rowers/braintreestuff.py | 45 ++++++++++++++++++++++++++++++++++++++-- rowers/models.py | 2 +- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/rowers/braintreestuff.py b/rowers/braintreestuff.py index 3bd84cd9..19cb6a86 100644 --- a/rowers/braintreestuff.py +++ b/rowers/braintreestuff.py @@ -1,9 +1,10 @@ -from rowers.models import Rower, PaidPlan, CoachingGroup +from rowers.models import Rower, PaidPlan, CoachingGroup, iDokladToken from rowers.utils import ProcessorCustomerError from rowsandall_app.settings import ( BRAINTREE_MERCHANT_ID, BRAINTREE_PUBLIC_KEY, BRAINTREE_PRIVATE_KEY, BRAINTREE_SANDBOX_MERCHANT_ID, BRAINTREE_SANDBOX_PUBLIC_KEY, - BRAINTREE_SANDBOX_PRIVATE_KEY, BRAINTREE_MERCHANT_ACCOUNT_ID + BRAINTREE_SANDBOX_PRIVATE_KEY, BRAINTREE_MERCHANT_ACCOUNT_ID, + IDOKLAD_CLIENT_ID, IDOKLAD_CLIENT_SECRET, IDOKLAD_REDIRECT_URI, ) import pandas as pd from rowers.utils import dologging @@ -52,6 +53,46 @@ else: ) ) +def idoklad_token(): + try: + token = iDokladToken.objects.get(id=1) + except iDokladToken.DoesNotExist: + return None + + if token.updated_at + datetime.timedelta(seconds=token.expires_in) < timezone.now(): + headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + } + + data = { + 'grant_type': 'refresh_token', + 'client_id': IDOKLAD_CLIENT_ID, + 'client_secret': IDOKLAD_CLIENT_SECRET, + 'scope': 'eet offline_access', + 'refresh_token': token.refresh_token, + } + + response = requests.post('https://app.idoklad.cz/identity/server/connect/token', headers=headers, data=data) + + if response.status_code == 200: + token = response.json() + token['updated_at'] = timezone.now() + iDokladToken.objects.filter(id=1).update(**token) + else: + return None + + return token + +def prepare_invoice(): + token = idoklad_token() + if token is None: + return None + + data = { + 'templateId': 1, + } + + def process_webhook(notification): if not settings.TESTING: # pragma: no cover diff --git a/rowers/models.py b/rowers/models.py index 30cbfc78..0631182a 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -5374,5 +5374,5 @@ class iDokladToken(models.Model): expires_in = models.IntegerField() # Store token expiry duration in seconds def __str__(self): - return f"iDoklad Token updated at {self.updated_at}" + return f"iDoklad Token updated at {self.updated_at}, expires at {self.updated_at+datetime.timedelta(seconds=self.expires_in)}" From 3955061e3f8756859f52921a04d2d159a8392b71 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 17 Nov 2024 17:41:14 +0100 Subject: [PATCH 05/32] got get_contacts working --- rowers/braintreestuff.py | 39 ------------------------------------ rowers/models.py | 2 ++ rowers/views/paymentviews.py | 1 + 3 files changed, 3 insertions(+), 39 deletions(-) diff --git a/rowers/braintreestuff.py b/rowers/braintreestuff.py index 19cb6a86..7cb162d1 100644 --- a/rowers/braintreestuff.py +++ b/rowers/braintreestuff.py @@ -53,45 +53,6 @@ else: ) ) -def idoklad_token(): - try: - token = iDokladToken.objects.get(id=1) - except iDokladToken.DoesNotExist: - return None - - if token.updated_at + datetime.timedelta(seconds=token.expires_in) < timezone.now(): - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - } - - data = { - 'grant_type': 'refresh_token', - 'client_id': IDOKLAD_CLIENT_ID, - 'client_secret': IDOKLAD_CLIENT_SECRET, - 'scope': 'eet offline_access', - 'refresh_token': token.refresh_token, - } - - response = requests.post('https://app.idoklad.cz/identity/server/connect/token', headers=headers, data=data) - - if response.status_code == 200: - token = response.json() - token['updated_at'] = timezone.now() - iDokladToken.objects.filter(id=1).update(**token) - else: - return None - - return token - -def prepare_invoice(): - token = idoklad_token() - if token is None: - return None - - data = { - 'templateId': 1, - } - def process_webhook(notification): diff --git a/rowers/models.py b/rowers/models.py index 0631182a..bd99bb13 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -5369,6 +5369,8 @@ class ForceCurveAnalysis(models.Model): class iDokladToken(models.Model): access_token = models.CharField(max_length=512) refresh_token = models.CharField(max_length=512) + id_token = models.CharField(max_length=512) + token_type = models.CharField(max_length=512) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) expires_in = models.IntegerField() # Store token expiry duration in seconds diff --git a/rowers/views/paymentviews.py b/rowers/views/paymentviews.py index f69942b0..241091c1 100644 --- a/rowers/views/paymentviews.py +++ b/rowers/views/paymentviews.py @@ -58,6 +58,7 @@ def process_idokladcallback(request): t.acces_token = result['access_token'], t.refresh_token = result['refresh_token'] t.expires_in = result['expires_in'] + t.id_token = result['id_token'] t.save() except iDokladToken.DoesNotExist: t = iDokladToken( From 9215e8b0bda3c8cf0f14046c859dace062edc15a Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 17 Nov 2024 17:41:30 +0100 Subject: [PATCH 06/32] adding idoklad.py --- rowers/idoklad.py | 98 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 rowers/idoklad.py diff --git a/rowers/idoklad.py b/rowers/idoklad.py new file mode 100644 index 00000000..d8779983 --- /dev/null +++ b/rowers/idoklad.py @@ -0,0 +1,98 @@ +import requests +import json +from requests.auth import HTTPBasicAuth +import urllib.parse +from rowers.utils import dologging +import datetime +from django.utils import timezone + +from rowsandall_app.settings import ( + IDOKLAD_CLIENT_ID, IDOKLAD_CLIENT_SECRET, + ) + +contacts_url = 'https://api.idoklad.cz/v3/Contacts' + +from rowers.models import iDokladToken + +def idoklad_token(): + try: + token = iDokladToken.objects.get(id=1) + except iDokladToken.DoesNotExist: + return None + + if token.updated_at + datetime.timedelta(seconds=token.expires_in) < timezone.now(): + headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + } + + data = { + 'grant_type': 'refresh_token', + 'client_id': IDOKLAD_CLIENT_ID, + 'client_secret': IDOKLAD_CLIENT_SECRET, + 'scope': 'eet offline_access', + 'refresh_token': token.refresh_token, + } + + response = requests.post('https://identity.idoklad.cz/server/connect/token', headers=headers, data=data) + + if response.status_code == 200: + token = response.json() + token['updated_at'] = timezone.now() + iDokladToken.objects.filter(id=1).update(**token) + return token + else: + return None + + return token + +def prepare_invoice(): + token = idoklad_token() + if token is None: + return None + + data = { + 'templateId': 1, + } + +def get_contacts(rower): + token = idoklad_token() + if token is None: + return None + headers = { + 'Authorization': 'Bearer {t}'.format(t=token.access_token), + } + + url = contacts_url+'?filter=(Email~eq~'+urllib.parse.quote(rower.user.email)+')' + dologging('idoklad.log','Searching Contact url: '+str(url)) + + res = requests.get(url, headers=headers) + + dologging('idoklad.log','Searching Contact Status code '+str(res.status_code)+'\n') + + if res.status_code != 200: # pragma: no cover + return None + + + dologging('idoklad.log','Status Code '+json.dumps(res.json())+'\n') + + data = res.json()['Data']['Items'] + + if len(data) >= 1: + r = data[0] + return r['Id'] + + return None # pragma + +def create_contact(rower): + post_data = { + 'City': rower.city, + 'CompanyName': rower.user.first_name+" "+rower.user.last_name, + 'CountryId': rower.country.code, # country id + 'Email': rower.user.email, + 'Firstname': rower.user.first_name, + 'PostalCode': rower.postal_code, + 'Street': rower.street_address, + 'Surname': rower.user.last_name, + 'DeliveryAddresses': [] + } + From 97cc0594fc0be7190c486120b8de50c54cd037a7 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 18 Nov 2024 19:56:52 +0100 Subject: [PATCH 07/32] adding create_contact --- rowers/idoklad.py | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/rowers/idoklad.py b/rowers/idoklad.py index d8779983..6c04c45a 100644 --- a/rowers/idoklad.py +++ b/rowers/idoklad.py @@ -14,6 +14,16 @@ contacts_url = 'https://api.idoklad.cz/v3/Contacts' from rowers.models import iDokladToken +idoklad_countries = json.loads(open('rowers/idoklad_countries.json').read())["Data"]["Items"] + +def get_country_id(code): + for c in idoklad_countries: + if c['Code'] == code: + return c['Id'] + return 1 + + + def idoklad_token(): try: token = iDokladToken.objects.get(id=1) @@ -38,7 +48,7 @@ def idoklad_token(): if response.status_code == 200: token = response.json() token['updated_at'] = timezone.now() - iDokladToken.objects.filter(id=1).update(**token) + token = iDokladToken.objects.filter(id=1).update(**token) return token else: return None @@ -84,10 +94,14 @@ def get_contacts(rower): return None # pragma def create_contact(rower): - post_data = { + token = idoklad_token() + if token is None: + return None + + data = { 'City': rower.city, 'CompanyName': rower.user.first_name+" "+rower.user.last_name, - 'CountryId': rower.country.code, # country id + 'CountryId': get_country_id(rower.country.code), 'Email': rower.user.email, 'Firstname': rower.user.first_name, 'PostalCode': rower.postal_code, @@ -95,4 +109,27 @@ def create_contact(rower): 'Surname': rower.user.last_name, 'DeliveryAddresses': [] } - + + if rower.country.numeric is None: + data['CountryId'] = 1 + + + + dologging('idoklad.log','Creating idoklad contact for '+str(rower.user.email)+'\n') + + headers = { + 'Authorization': 'Bearer {t}'.format(t=token.access_token), + "Content-Type": "application/json", + "Accept": "application/json", + } + + res = requests.post(contacts_url, json=data, headers=headers) + + if res.status_code not in [200, 201]: + return 0 + + id = res.json()['Data']['Id'] + + return id + + From 21299c534771561ff554ede7ef24c46d680baff0 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 18 Nov 2024 19:57:31 +0100 Subject: [PATCH 08/32] fix --- rowers/idoklad_countries.json | 2212 +++++++++++++++++++++++++++++++++ 1 file changed, 2212 insertions(+) create mode 100644 rowers/idoklad_countries.json diff --git a/rowers/idoklad_countries.json b/rowers/idoklad_countries.json new file mode 100644 index 00000000..3e388018 --- /dev/null +++ b/rowers/idoklad_countries.json @@ -0,0 +1,2212 @@ +{ + "Data": { + "Items": [ + { + "Code": "SK", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 1, + "IsEuMember": true, + "Name": "Slovensko", + "NameEnglish": "Slovakia", + "NameGerman": "Slowakei", + "NameSlovak": "Slovensko" + }, + { + "Code": "CZ", + "CurrencyId": 1, + "DateLastChange": "2022-10-25", + "Id": 2, + "IsEuMember": true, + "Name": "Česká republika", + "NameEnglish": "Czechia", + "NameGerman": "Tschechische Republik", + "NameSlovak": "Česká republika" + }, + { + "Code": "AF", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 3, + "IsEuMember": false, + "Name": "Afghánistán", + "NameEnglish": "Afghanistan", + "NameGerman": "Afghanistan", + "NameSlovak": "Afganistan" + }, + { + "Code": "AL", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 4, + "IsEuMember": false, + "Name": "Albánie", + "NameEnglish": "Albania", + "NameGerman": "Albanien", + "NameSlovak": "Albánsko" + }, + { + "Code": "AQ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 5, + "IsEuMember": false, + "Name": "Antarktida", + "NameEnglish": "Antarctica", + "NameGerman": "Antarktis", + "NameSlovak": "Antarktída" + }, + { + "Code": "DZ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 6, + "IsEuMember": false, + "Name": "Alžírsko", + "NameEnglish": "Algeria", + "NameGerman": "Algerien", + "NameSlovak": "Alžírsko" + }, + { + "Code": "AS", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 7, + "IsEuMember": false, + "Name": "Americká Samoa", + "NameEnglish": "American Samoa", + "NameGerman": "Amerikanisch-Samoa", + "NameSlovak": "Americká Samoa" + }, + { + "Code": "AD", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 8, + "IsEuMember": false, + "Name": "Andorra", + "NameEnglish": "Andorra", + "NameGerman": "Andorra", + "NameSlovak": "Andorra" + }, + { + "Code": "AO", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 9, + "IsEuMember": false, + "Name": "Angola", + "NameEnglish": "Angola", + "NameGerman": "Angola", + "NameSlovak": "Angola" + }, + { + "Code": "AG", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 10, + "IsEuMember": false, + "Name": "Antigua a Barbuda", + "NameEnglish": "Antigua and Barbuda", + "NameGerman": "Antigua und Barbuda", + "NameSlovak": "Antigua a Barbuda" + }, + { + "Code": "AZ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 11, + "IsEuMember": false, + "Name": "Ázerbájdžán", + "NameEnglish": "Azerbaijan", + "NameGerman": "Aserbaidschan", + "NameSlovak": "Azerbajdžan" + }, + { + "Code": "AR", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 12, + "IsEuMember": false, + "Name": "Argentina", + "NameEnglish": "Argentina", + "NameGerman": "Argentinien", + "NameSlovak": "Argentína" + }, + { + "Code": "AU", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 13, + "IsEuMember": false, + "Name": "Austrálie", + "NameEnglish": "Australia", + "NameGerman": "Australien", + "NameSlovak": "Austrália" + }, + { + "Code": "AT", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 14, + "IsEuMember": true, + "Name": "Rakousko", + "NameEnglish": "Austria", + "NameGerman": "Österreich", + "NameSlovak": "Rakúsko" + }, + { + "Code": "BS", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 15, + "IsEuMember": false, + "Name": "Bahamy", + "NameEnglish": "Bahamas (The)", + "NameGerman": "Bahamas", + "NameSlovak": "Bahamy" + }, + { + "Code": "BH", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 16, + "IsEuMember": false, + "Name": "Bahrajn", + "NameEnglish": "Bahrain", + "NameGerman": "Bahrain", + "NameSlovak": "Bahrajn" + }, + { + "Code": "BD", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 17, + "IsEuMember": false, + "Name": "Bangladéš", + "NameEnglish": "Bangladesh", + "NameGerman": "Bangladesch", + "NameSlovak": "Bangladéš" + }, + { + "Code": "AM", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 18, + "IsEuMember": false, + "Name": "Arménie", + "NameEnglish": "Armenia", + "NameGerman": "Armenien", + "NameSlovak": "Arménsko" + }, + { + "Code": "BB", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 19, + "IsEuMember": false, + "Name": "Barbados", + "NameEnglish": "Barbados", + "NameGerman": "Barbados", + "NameSlovak": "Barbados" + }, + { + "Code": "BE", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 20, + "IsEuMember": true, + "Name": "Belgie", + "NameEnglish": "Belgium", + "NameGerman": "Belgien ", + "NameSlovak": "Belgicko" + }, + { + "Code": "BM", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 21, + "IsEuMember": false, + "Name": "Bermudy", + "NameEnglish": "Bermuda", + "NameGerman": "Bermuda", + "NameSlovak": "Bermudy" + }, + { + "Code": "BT", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 22, + "IsEuMember": false, + "Name": "Bhútán", + "NameEnglish": "Bhutan", + "NameGerman": "Bhutan", + "NameSlovak": "Bhután" + }, + { + "Code": "BO", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 23, + "IsEuMember": false, + "Name": "Bolívie", + "NameEnglish": "Bolivia (Plurinational State of)", + "NameGerman": "Bolivien", + "NameSlovak": "Bolívia" + }, + { + "Code": "BA", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 24, + "IsEuMember": false, + "Name": "Bosna a Hercegovina", + "NameEnglish": "Bosnia and Herzegovina", + "NameGerman": " Bosnien und Herzegowina", + "NameSlovak": "Bosna a Hercegovina" + }, + { + "Code": "BW", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 25, + "IsEuMember": false, + "Name": "Botswana", + "NameEnglish": "Botswana", + "NameGerman": "Botswana", + "NameSlovak": "Botswana" + }, + { + "Code": "BV", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 26, + "IsEuMember": false, + "Name": "Bouvetův ostrov", + "NameEnglish": "Bouvet Island", + "NameGerman": "Bouvetinsel", + "NameSlovak": "Bouvetov ostrov" + }, + { + "Code": "BR", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 27, + "IsEuMember": false, + "Name": "Brazílie", + "NameEnglish": "Brazil", + "NameGerman": "Brasilien", + "NameSlovak": "Brazília" + }, + { + "Code": "BZ", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 28, + "IsEuMember": false, + "Name": "Belize", + "NameEnglish": "Belize", + "NameGerman": "Belize", + "NameSlovak": "Belize" + }, + { + "Code": "IO", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 29, + "IsEuMember": false, + "Name": "Britské indickooceánské území", + "NameEnglish": "British Indian Ocean Territory (the)\r\n", + "NameGerman": "Britisches Territorium im Indischen Ozean", + "NameSlovak": "Britské indickooceánske územie" + }, + { + "Code": "SB", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 30, + "IsEuMember": false, + "Name": "Šalomounovy ostrovy", + "NameEnglish": "Solomon Islands", + "NameGerman": "Salomonen", + "NameSlovak": "Šalamúnove ostrovy" + }, + { + "Code": "VG", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 31, + "IsEuMember": false, + "Name": "Britské Panenské ostrovy", + "NameEnglish": "Virgin Islands (British)", + "NameGerman": "Britische Jungferninseln", + "NameSlovak": "Britské Panenské ostrovy" + }, + { + "Code": "XK", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 32, + "IsEuMember": false, + "Name": "Kosovo", + "NameEnglish": "Republic of Kosovo", + "NameGerman": "Kosovo", + "NameSlovak": "Kosovo" + }, + { + "Code": "BN", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 33, + "IsEuMember": false, + "Name": "Brunej", + "NameEnglish": "Brunei Darussalam", + "NameGerman": "Brunei", + "NameSlovak": "Brunej" + }, + { + "Code": "BG", + "CurrencyId": 3, + "DateLastChange": "1753-01-01", + "Id": 34, + "IsEuMember": true, + "Name": "Bulharsko", + "NameEnglish": "Bulgaria", + "NameGerman": "Bulgarien", + "NameSlovak": "Bulharsko" + }, + { + "Code": "MM", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 35, + "IsEuMember": false, + "Name": "Myanmar", + "NameEnglish": "Myanmar", + "NameGerman": "Myanmar", + "NameSlovak": "Mjanmarsko" + }, + { + "Code": "BI", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 36, + "IsEuMember": false, + "Name": "Burundi", + "NameEnglish": "Burundi", + "NameGerman": "Burundi", + "NameSlovak": "Burundi" + }, + { + "Code": "BY", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 37, + "IsEuMember": false, + "Name": "Bělorusko", + "NameEnglish": "Belarus", + "NameGerman": "Belarus", + "NameSlovak": "Bielorusko" + }, + { + "Code": "KH", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 38, + "IsEuMember": false, + "Name": "Kambodža", + "NameEnglish": "Cambodia", + "NameGerman": "Kambodscha", + "NameSlovak": "Kambodža" + }, + { + "Code": "CM", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 39, + "IsEuMember": false, + "Name": "Kamerun", + "NameEnglish": "Cameroon", + "NameGerman": "Kamerun", + "NameSlovak": "Kamerun" + }, + { + "Code": "CA", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 40, + "IsEuMember": false, + "Name": "Kanada", + "NameEnglish": "Canada", + "NameGerman": "Kanada", + "NameSlovak": "Kanada" + }, + { + "Code": "CV", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 41, + "IsEuMember": false, + "Name": "Kapverdy", + "NameEnglish": "Cape Verde", + "NameGerman": "Kap Verde", + "NameSlovak": "Kapverdy" + }, + { + "Code": "KY", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 42, + "IsEuMember": false, + "Name": "Kajmanské ostrovy", + "NameEnglish": "Cayman Islands (the)", + "NameGerman": "Kaimaninseln", + "NameSlovak": "Kajmanské ostrovy" + }, + { + "Code": "CF", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 43, + "IsEuMember": false, + "Name": "Středoafrická republika", + "NameEnglish": "Central African Republic (the)", + "NameGerman": "Zentralafrikanische Republik", + "NameSlovak": "Stredoafrická republika" + }, + { + "Code": "LK", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 44, + "IsEuMember": false, + "Name": "Šrí Lanka", + "NameEnglish": "Sri Lanka", + "NameGerman": "Sri Lanka", + "NameSlovak": "Srí Lanka" + }, + { + "Code": "TD", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 45, + "IsEuMember": false, + "Name": "Čad", + "NameEnglish": "Chad", + "NameGerman": "Tschad", + "NameSlovak": "Čad" + }, + { + "Code": "CL", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 46, + "IsEuMember": false, + "Name": "Chile", + "NameEnglish": "Chile", + "NameGerman": "Chile ", + "NameSlovak": "Čile" + }, + { + "Code": "CN", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 47, + "IsEuMember": false, + "Name": "Čína", + "NameEnglish": "China", + "NameGerman": "China", + "NameSlovak": "Čína" + }, + { + "Code": "TW", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 48, + "IsEuMember": false, + "Name": "Tchaj-wan", + "NameEnglish": "Taiwan (Province of China)", + "NameGerman": "Taiwan", + "NameSlovak": "Taiwan" + }, + { + "Code": "CX", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 49, + "IsEuMember": false, + "Name": "Vánoční ostrov", + "NameEnglish": "Christmas Island", + "NameGerman": "Weihnachtsinsel", + "NameSlovak": "Vianočný ostrov" + }, + { + "Code": "CC", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 50, + "IsEuMember": false, + "Name": "Kokosové (Keelingovy) ostrovy", + "NameEnglish": "Cocos (Keeling) Islands (the)", + "NameGerman": "Kokosinseln (Keelinginseln)", + "NameSlovak": "Kokosové (Keelingove) ostrovy" + }, + { + "Code": "CO", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 51, + "IsEuMember": false, + "Name": "Kolumbie", + "NameEnglish": "Colombia", + "NameGerman": "Kolumbien", + "NameSlovak": "Kolumbia" + }, + { + "Code": "KM", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 52, + "IsEuMember": false, + "Name": "Komory", + "NameEnglish": "Comoros (the)", + "NameGerman": "Komoren", + "NameSlovak": "Komory" + }, + { + "Code": "YT", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 53, + "IsEuMember": false, + "Name": "Mayotte", + "NameEnglish": "Mayotte", + "NameGerman": "Mayotte", + "NameSlovak": "Mayotte" + }, + { + "Code": "CG", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 54, + "IsEuMember": false, + "Name": "Konžská republika", + "NameEnglish": "Congo (the)", + "NameGerman": "Republik Kongo", + "NameSlovak": "Konžská republika" + }, + { + "Code": "CD", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 55, + "IsEuMember": false, + "Name": "Demokratická republika Kongo", + "NameEnglish": "Congo (the Democratic Republic of the)", + "NameGerman": "Demokratische Republik Kongo", + "NameSlovak": "Konžská demokratická republika" + }, + { + "Code": "CK", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 56, + "IsEuMember": false, + "Name": "Cookovy ostrovy", + "NameEnglish": "Cook Islands (the)", + "NameGerman": "Cookinseln", + "NameSlovak": "Cookove ostrovy" + }, + { + "Code": "CR", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 57, + "IsEuMember": false, + "Name": "Kostarika", + "NameEnglish": "Costa Rica", + "NameGerman": "Costa Rica", + "NameSlovak": "Kostarika" + }, + { + "Code": "HR", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 58, + "IsEuMember": true, + "Name": "Chorvatsko", + "NameEnglish": "Croatia", + "NameGerman": "Kroatien", + "NameSlovak": "Chorvátsko" + }, + { + "Code": "CU", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 59, + "IsEuMember": false, + "Name": "Kuba", + "NameEnglish": "Cuba", + "NameGerman": "Kuba", + "NameSlovak": "Kuba" + }, + { + "Code": "CY", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 60, + "IsEuMember": true, + "Name": "Kypr", + "NameEnglish": "Cyprus", + "NameGerman": "Zypern", + "NameSlovak": "Cyprus" + }, + { + "Code": "BJ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 61, + "IsEuMember": false, + "Name": "Benin", + "NameEnglish": "Benin", + "NameGerman": "Benin", + "NameSlovak": "Benin" + }, + { + "Code": "DK", + "CurrencyId": 4, + "DateLastChange": "1753-01-01", + "Id": 62, + "IsEuMember": true, + "Name": "Dánsko", + "NameEnglish": "Denmark", + "NameGerman": "Dänemark", + "NameSlovak": "Dánsko" + }, + { + "Code": "DM", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 63, + "IsEuMember": false, + "Name": "Dominika", + "NameEnglish": "Dominica", + "NameGerman": "Dominica", + "NameSlovak": "Dominika" + }, + { + "Code": "DO", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 64, + "IsEuMember": false, + "Name": "Dominikánská republika", + "NameEnglish": "Dominican Republic (the)", + "NameGerman": "Dominikanische Republik", + "NameSlovak": "Dominikánska republika" + }, + { + "Code": "EC", + "CurrencyId": 11, + "DateLastChange": "1753-01-01", + "Id": 65, + "IsEuMember": false, + "Name": "Ekvádor", + "NameEnglish": "Ecuador", + "NameGerman": "Ecuador", + "NameSlovak": "Ekvádor" + }, + { + "Code": "SV", + "CurrencyId": 11, + "DateLastChange": "1753-01-01", + "Id": 66, + "IsEuMember": false, + "Name": "Salvador", + "NameEnglish": "El Salvador", + "NameGerman": "El Salvador", + "NameSlovak": "Salvador" + }, + { + "Code": "GQ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 67, + "IsEuMember": false, + "Name": "Rovníková Guinea", + "NameEnglish": "Equatorial Guinea", + "NameGerman": "Äquatorialguinea", + "NameSlovak": "Rovníková Guinea" + }, + { + "Code": "ET", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 68, + "IsEuMember": false, + "Name": "Etiopie", + "NameEnglish": "Ethiopia", + "NameGerman": "Äthiopien", + "NameSlovak": "Etiópia" + }, + { + "Code": "ER", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 69, + "IsEuMember": false, + "Name": "Eritrea", + "NameEnglish": "Eritrea", + "NameGerman": "Eritrea", + "NameSlovak": "Eritrejský štát" + }, + { + "Code": "EE", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 70, + "IsEuMember": true, + "Name": "Estonsko", + "NameEnglish": "Estonia", + "NameGerman": "Estland", + "NameSlovak": "Estónsko" + }, + { + "Code": "FO", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 71, + "IsEuMember": false, + "Name": "Faerské ostrovy", + "NameEnglish": "Faroe Islands (the)", + "NameGerman": "Färöer", + "NameSlovak": "Faerské ostrovy" + }, + { + "Code": "FK", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 72, + "IsEuMember": false, + "Name": "Falklandy", + "NameEnglish": "Falkland Islands (the) (Malvinas)", + "NameGerman": "Falklandinseln", + "NameSlovak": "Falklandy" + }, + { + "Code": "GS", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 73, + "IsEuMember": false, + "Name": "Jižní Georgie a Jižní Sandwichovy ostrovy", + "NameEnglish": "South Georgia and the South Sandwich Islands", + "NameGerman": "Südgeorgien und die Südlichen Sandwichinseln", + "NameSlovak": "Južná Georgia a Južné Sandwichove ostrovy" + }, + { + "Code": "FJ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 74, + "IsEuMember": false, + "Name": "Fidži", + "NameEnglish": "Fiji", + "NameGerman": "Fidschi", + "NameSlovak": "Fidži" + }, + { + "Code": "FI", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 75, + "IsEuMember": true, + "Name": "Finsko", + "NameEnglish": "Finland", + "NameGerman": "Finnland", + "NameSlovak": "Fínsko" + }, + { + "Code": "AX", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 76, + "IsEuMember": false, + "Name": "Alandy", + "NameEnglish": "Åland Islands", + "NameGerman": "Åland", + "NameSlovak": "Alandy" + }, + { + "Code": "FR", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 77, + "IsEuMember": true, + "Name": "Francie", + "NameEnglish": "France", + "NameGerman": "Frankreich", + "NameSlovak": "Francúzsko" + }, + { + "Code": "GF", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 78, + "IsEuMember": false, + "Name": "Francouzská Guyana", + "NameEnglish": "French Guiana", + "NameGerman": "Französisch-Guyana", + "NameSlovak": "Francúzska Guyana" + }, + { + "Code": "PF", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 79, + "IsEuMember": false, + "Name": "Francouzská Polynésie", + "NameEnglish": "French Polynesia", + "NameGerman": "Französisch-Polynesien", + "NameSlovak": "Francúzska Polynézia" + }, + { + "Code": "TF", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 80, + "IsEuMember": false, + "Name": "Francouzská jižní a antarktická území", + "NameEnglish": "French Southern Territories (the)", + "NameGerman": "Französisch Süd- und Antarktisgebiete", + "NameSlovak": "Francúzske južné a antarktické územia" + }, + { + "Code": "DJ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 81, + "IsEuMember": false, + "Name": "Džibutsko", + "NameEnglish": "Djibouti", + "NameGerman": "Dschibuti", + "NameSlovak": "Džibutsko" + }, + { + "Code": "GA", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 82, + "IsEuMember": false, + "Name": "Gabon", + "NameEnglish": "Gabon", + "NameGerman": "Gabon", + "NameSlovak": "Gabon" + }, + { + "Code": "GE", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 83, + "IsEuMember": false, + "Name": "Gruzie", + "NameEnglish": "Georgia", + "NameGerman": "Georgien", + "NameSlovak": "Gruzínska republika" + }, + { + "Code": "GM", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 84, + "IsEuMember": false, + "Name": "Gambie", + "NameEnglish": "Gambia (the)", + "NameGerman": "Gambia", + "NameSlovak": "Gambia" + }, + { + "Code": "PS", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 85, + "IsEuMember": false, + "Name": "Palestina", + "NameEnglish": "Palestine, State of", + "NameGerman": "Palästina", + "NameSlovak": "Palestína" + }, + { + "Code": "DE", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 86, + "IsEuMember": true, + "Name": "Německo", + "NameEnglish": "Germany", + "NameGerman": "Deutschland", + "NameSlovak": "Nemecko" + }, + { + "Code": "GH", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 87, + "IsEuMember": false, + "Name": "Ghana", + "NameEnglish": "Ghana", + "NameGerman": "Ghana", + "NameSlovak": "Ghana" + }, + { + "Code": "GI", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 88, + "IsEuMember": false, + "Name": "Gibraltar", + "NameEnglish": "Gibraltar", + "NameGerman": "Gibraltar", + "NameSlovak": "Gibraltár" + }, + { + "Code": "KI", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 89, + "IsEuMember": false, + "Name": "Kiribati", + "NameEnglish": "Kiribati", + "NameGerman": "Kiribati", + "NameSlovak": "Kiribati" + }, + { + "Code": "GR", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 90, + "IsEuMember": true, + "Name": "Řecko", + "NameEnglish": "Greece", + "NameGerman": "Griechenland", + "NameSlovak": "Grécko" + }, + { + "Code": "GL", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 91, + "IsEuMember": false, + "Name": "Grónsko", + "NameEnglish": "Greenland", + "NameGerman": "Grönland", + "NameSlovak": "Grónsko" + }, + { + "Code": "GD", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 92, + "IsEuMember": false, + "Name": "Grenada", + "NameEnglish": "Grenada", + "NameGerman": "Grenada", + "NameSlovak": "Grenada" + }, + { + "Code": "GP", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 93, + "IsEuMember": false, + "Name": "Guadeloupe", + "NameEnglish": "Guadeloupe", + "NameGerman": "Guadeloupe", + "NameSlovak": "Guadeloupe" + }, + { + "Code": "GU", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 94, + "IsEuMember": false, + "Name": "Guam", + "NameEnglish": "Guam", + "NameGerman": "Guam", + "NameSlovak": "Guam" + }, + { + "Code": "GT", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 95, + "IsEuMember": false, + "Name": "Guatemala", + "NameEnglish": "Guatemala", + "NameGerman": "Guatemala", + "NameSlovak": "Guatemala" + }, + { + "Code": "GN", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 96, + "IsEuMember": false, + "Name": "Guinea", + "NameEnglish": "Guinea", + "NameGerman": "Guinea", + "NameSlovak": "Guinea" + }, + { + "Code": "GY", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 97, + "IsEuMember": false, + "Name": "Guyana", + "NameEnglish": "Guyana", + "NameGerman": "Guyana", + "NameSlovak": "Guyana" + }, + { + "Code": "HT", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 98, + "IsEuMember": false, + "Name": "Haiti", + "NameEnglish": "Haiti", + "NameGerman": "Haiti", + "NameSlovak": "Haiti" + }, + { + "Code": "HM", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 99, + "IsEuMember": false, + "Name": "Heardův ostrov a MacDonaldovy ostrovy", + "NameEnglish": "Heard Island and McDonald Islands", + "NameGerman": "Heard und die McDonaldinseln", + "NameSlovak": "Heardov ostrov a Macdonaldove ostrovy" + }, + { + "Code": "VA", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 100, + "IsEuMember": false, + "Name": "Vatikán", + "NameEnglish": "Holy See (the)", + "NameGerman": "Vatikanstadt", + "NameSlovak": "Vatikán" + }, + { + "Code": "HN", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 101, + "IsEuMember": false, + "Name": "Honduras", + "NameEnglish": "Honduras", + "NameGerman": "Honduras", + "NameSlovak": "Honduras" + }, + { + "Code": "HK", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 102, + "IsEuMember": false, + "Name": "Hongkong", + "NameEnglish": "Hong Kong", + "NameGerman": "Hongkong", + "NameSlovak": "Hongkong" + }, + { + "Code": "HU", + "CurrencyId": 5, + "DateLastChange": "1753-01-01", + "Id": 103, + "IsEuMember": true, + "Name": "Maďarsko", + "NameEnglish": "Hungary", + "NameGerman": "Ungarn", + "NameSlovak": "Maďarsko" + }, + { + "Code": "IS", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 104, + "IsEuMember": false, + "Name": "Island", + "NameEnglish": "Iceland", + "NameGerman": "Island", + "NameSlovak": "Island" + }, + { + "Code": "IN", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 105, + "IsEuMember": false, + "Name": "Indie", + "NameEnglish": "India", + "NameGerman": "Indien", + "NameSlovak": "India" + }, + { + "Code": "ID", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 106, + "IsEuMember": false, + "Name": "Indonésie", + "NameEnglish": "Indonesia", + "NameGerman": "Indonesien", + "NameSlovak": "Indonézia" + }, + { + "Code": "IR", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 107, + "IsEuMember": false, + "Name": "Írán", + "NameEnglish": "Iran (Islamic Republic of)", + "NameGerman": "Iran", + "NameSlovak": "Irán" + }, + { + "Code": "IQ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 108, + "IsEuMember": false, + "Name": "Irák", + "NameEnglish": "Iraq", + "NameGerman": "Irak", + "NameSlovak": "Irak" + }, + { + "Code": "IE", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 109, + "IsEuMember": true, + "Name": "Irsko", + "NameEnglish": "Ireland", + "NameGerman": "Irland", + "NameSlovak": "Írsko" + }, + { + "Code": "IL", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 110, + "IsEuMember": false, + "Name": "Izrael", + "NameEnglish": "Israel", + "NameGerman": "Israel", + "NameSlovak": "Izrael" + }, + { + "Code": "IT", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 111, + "IsEuMember": true, + "Name": "Itálie", + "NameEnglish": "Italy", + "NameGerman": "Italien", + "NameSlovak": "Taliansko" + }, + { + "Code": "CI", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 112, + "IsEuMember": false, + "Name": "Pobřeží slonoviny", + "NameEnglish": "Côte d'Ivoire", + "NameGerman": "Côte d'Ivoire", + "NameSlovak": "Pobrežie Slonoviny" + }, + { + "Code": "JM", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 113, + "IsEuMember": false, + "Name": "Jamajka", + "NameEnglish": "Jamaica", + "NameGerman": "Jamaika", + "NameSlovak": "Jamajka" + }, + { + "Code": "JP", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 114, + "IsEuMember": false, + "Name": "Japonsko", + "NameEnglish": "Japan", + "NameGerman": "Japan", + "NameSlovak": "Japonsko" + }, + { + "Code": "KZ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 115, + "IsEuMember": false, + "Name": "Kazachstán", + "NameEnglish": "Kazakhstan", + "NameGerman": "Kasachstan", + "NameSlovak": "Kazachstan" + }, + { + "Code": "JO", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 116, + "IsEuMember": false, + "Name": "Jordánsko", + "NameEnglish": "Jordan", + "NameGerman": "Jordanien", + "NameSlovak": "Jordánsko" + }, + { + "Code": "KE", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 117, + "IsEuMember": false, + "Name": "Keňa", + "NameEnglish": "Kenya", + "NameGerman": "Kenia", + "NameSlovak": "Keňa" + }, + { + "Code": "KP", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 118, + "IsEuMember": false, + "Name": "Korejská lidově demokratická republika", + "NameEnglish": "Korea (the Democratic People's Republic of)", + "NameGerman": "Demokratische Volksrepublik Korea", + "NameSlovak": "Kórejská ľudovodemokratická republika" + }, + { + "Code": "KR", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 119, + "IsEuMember": false, + "Name": "Korejská republika", + "NameEnglish": "Korea (the Republic of)", + "NameGerman": "Republik Korea", + "NameSlovak": "Kórejská republika" + }, + { + "Code": "KW", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 120, + "IsEuMember": false, + "Name": "Kuvajt", + "NameEnglish": "Kuwait", + "NameGerman": "Kuwait", + "NameSlovak": "Kuvajt" + }, + { + "Code": "KG", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 121, + "IsEuMember": false, + "Name": "Kyrgyzstán", + "NameEnglish": "Kyrgyzstan", + "NameGerman": "Kirgisistan", + "NameSlovak": "Kirgizsko" + }, + { + "Code": "LA", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 122, + "IsEuMember": false, + "Name": "Laos", + "NameEnglish": "Lao People's Democratic Republic (the)", + "NameGerman": "Laos", + "NameSlovak": "Laos" + }, + { + "Code": "LB", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 123, + "IsEuMember": false, + "Name": "Libanon", + "NameEnglish": "Lebanon", + "NameGerman": "Libanon", + "NameSlovak": "Libanon" + }, + { + "Code": "LS", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 124, + "IsEuMember": false, + "Name": "Lesotho", + "NameEnglish": "Lesotho", + "NameGerman": "Lesotho", + "NameSlovak": "Lesotho" + }, + { + "Code": "LV", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 125, + "IsEuMember": true, + "Name": "Lotyšsko", + "NameEnglish": "Latvia", + "NameGerman": "Lettland", + "NameSlovak": "Lotyšsko" + }, + { + "Code": "LR", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 126, + "IsEuMember": false, + "Name": "Libérie", + "NameEnglish": "Liberia", + "NameGerman": "Liberia", + "NameSlovak": "Libéria" + }, + { + "Code": "LY", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 127, + "IsEuMember": false, + "Name": "Libye", + "NameEnglish": "Libya", + "NameGerman": "Libyen", + "NameSlovak": "Líbyjský štát" + }, + { + "Code": "LI", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 128, + "IsEuMember": false, + "Name": "Lichtenštejnsko", + "NameEnglish": "Liechtenstein", + "NameGerman": "Liechtenstein", + "NameSlovak": "Lichtenštajnsko" + }, + { + "Code": "LT", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 129, + "IsEuMember": true, + "Name": "Litva", + "NameEnglish": "Lithuania", + "NameGerman": "Litauen", + "NameSlovak": "Litva" + }, + { + "Code": "LU", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 130, + "IsEuMember": true, + "Name": "Lucembursko", + "NameEnglish": "Luxembourg", + "NameGerman": "Luxemburg", + "NameSlovak": "Luxembursko" + }, + { + "Code": "MO", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 131, + "IsEuMember": false, + "Name": "Macao", + "NameEnglish": "Macao", + "NameGerman": "Macao", + "NameSlovak": "Macao" + }, + { + "Code": "MG", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 132, + "IsEuMember": false, + "Name": "Madagaskar", + "NameEnglish": "Madagascar", + "NameGerman": "Madagaskar", + "NameSlovak": "Madagaskar" + }, + { + "Code": "MW", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 133, + "IsEuMember": false, + "Name": "Malawi", + "NameEnglish": "Malawi", + "NameGerman": "Malawi", + "NameSlovak": "Malawi" + }, + { + "Code": "MY", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 134, + "IsEuMember": false, + "Name": "Malajsie", + "NameEnglish": "Malaysia", + "NameGerman": "Malaysia", + "NameSlovak": "Malajzia" + }, + { + "Code": "MV", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 135, + "IsEuMember": false, + "Name": "Maledivy", + "NameEnglish": "Maldives", + "NameGerman": "Malediven", + "NameSlovak": "Maledivy" + }, + { + "Code": "ML", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 136, + "IsEuMember": false, + "Name": "Mali", + "NameEnglish": "Mali", + "NameGerman": "Mali", + "NameSlovak": "Mali" + }, + { + "Code": "MT", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 137, + "IsEuMember": true, + "Name": "Malta", + "NameEnglish": "Malta", + "NameGerman": "Malta", + "NameSlovak": "Malta" + }, + { + "Code": "MQ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 138, + "IsEuMember": false, + "Name": "Martinik", + "NameEnglish": "Martinique", + "NameGerman": "Martinique", + "NameSlovak": "Martinik" + }, + { + "Code": "MR", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 139, + "IsEuMember": false, + "Name": "Mauritánie", + "NameEnglish": "Mauritania", + "NameGerman": "Mauretanien", + "NameSlovak": "Mauritánia" + }, + { + "Code": "MU", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 140, + "IsEuMember": false, + "Name": "Mauricius", + "NameEnglish": "Mauritius", + "NameGerman": "Mauritius", + "NameSlovak": "Mauricius" + }, + { + "Code": "MX", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 141, + "IsEuMember": false, + "Name": "Mexiko", + "NameEnglish": "Mexico", + "NameGerman": "Mexiko", + "NameSlovak": "Mexiko" + }, + { + "Code": "MC", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 142, + "IsEuMember": false, + "Name": "Monako", + "NameEnglish": "Monaco", + "NameGerman": "Monaco", + "NameSlovak": "Monako" + }, + { + "Code": "MN", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 143, + "IsEuMember": false, + "Name": "Mongolsko", + "NameEnglish": "Mongolia", + "NameGerman": "Mongolei", + "NameSlovak": "Mongolská republika" + }, + { + "Code": "MD", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 144, + "IsEuMember": false, + "Name": "Moldavsko", + "NameEnglish": "Moldova (the Republic of)", + "NameGerman": "Moldau", + "NameSlovak": "Moldavsko" + }, + { + "Code": "ME", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 145, + "IsEuMember": false, + "Name": "Černá Hora", + "NameEnglish": "Montenegro", + "NameGerman": "Montenegro", + "NameSlovak": "Čierna Hora" + }, + { + "Code": "MS", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 146, + "IsEuMember": false, + "Name": "Montserrat", + "NameEnglish": "Montserrat", + "NameGerman": "Montserrat", + "NameSlovak": "Montserrat" + }, + { + "Code": "MA", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 147, + "IsEuMember": false, + "Name": "Maroko", + "NameEnglish": "Morocco", + "NameGerman": "Marokko", + "NameSlovak": "Maroko" + }, + { + "Code": "MZ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 148, + "IsEuMember": false, + "Name": "Mosambik", + "NameEnglish": "Mozambique", + "NameGerman": "Mosambik", + "NameSlovak": "Mozambik" + }, + { + "Code": "OM", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 149, + "IsEuMember": false, + "Name": "Omán", + "NameEnglish": "Oman", + "NameGerman": "Oman", + "NameSlovak": "Omán" + }, + { + "Code": "NA", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 150, + "IsEuMember": false, + "Name": "Namibie", + "NameEnglish": "Namibia", + "NameGerman": "Namibia", + "NameSlovak": "Namíbia" + }, + { + "Code": "NR", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 151, + "IsEuMember": false, + "Name": "Nauru", + "NameEnglish": "Nauru", + "NameGerman": "Nauru", + "NameSlovak": "Nauru" + }, + { + "Code": "NP", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 152, + "IsEuMember": false, + "Name": "Nepál", + "NameEnglish": "Nepal", + "NameGerman": "Nepal ", + "NameSlovak": "Nepál" + }, + { + "Code": "NL", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 153, + "IsEuMember": true, + "Name": "Nizozemsko", + "NameEnglish": "Netherlands (the)", + "NameGerman": "Niederlande", + "NameSlovak": "Holandsko" + }, + { + "Code": "AN", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 154, + "IsEuMember": false, + "Name": "Nizozemské Antily", + "NameEnglish": "Netherlands Antilles", + "NameGerman": "Niederländische Antillen", + "NameSlovak": "Holandské Antily" + }, + { + "Code": "AW", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 155, + "IsEuMember": false, + "Name": "Aruba", + "NameEnglish": "Aruba", + "NameGerman": "Aruba", + "NameSlovak": "Aruba" + }, + { + "Code": "NC", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 156, + "IsEuMember": false, + "Name": "Nová Kaledonie", + "NameEnglish": "New Caledonia", + "NameGerman": "Neukaledonien", + "NameSlovak": "Nová Kaledónia" + }, + { + "Code": "VU", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 157, + "IsEuMember": false, + "Name": "Vanuatu", + "NameEnglish": "Vanuatu", + "NameGerman": "Vanuatu", + "NameSlovak": "Vanuatu" + }, + { + "Code": "NZ", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 158, + "IsEuMember": false, + "Name": "Nový Zéland", + "NameEnglish": "New Zealand", + "NameGerman": "Neuseeland", + "NameSlovak": "Nový Zéland" + }, + { + "Code": "NI", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 159, + "IsEuMember": false, + "Name": "Nikaragua", + "NameEnglish": "Nicaragua", + "NameGerman": "Nicaragua", + "NameSlovak": "Nikaragua" + }, + { + "Code": "NE", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 160, + "IsEuMember": false, + "Name": "Niger", + "NameEnglish": "Niger (the)", + "NameGerman": "Niger", + "NameSlovak": "Niger" + }, + { + "Code": "NG", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 161, + "IsEuMember": false, + "Name": "Nigérie", + "NameEnglish": "Nigeria", + "NameGerman": "Nigeria", + "NameSlovak": "Nigéria" + }, + { + "Code": "NU", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 162, + "IsEuMember": false, + "Name": "Niue", + "NameEnglish": "Niue", + "NameGerman": "Niue", + "NameSlovak": "Niue" + }, + { + "Code": "NF", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 163, + "IsEuMember": false, + "Name": "Norfolk", + "NameEnglish": "Norfolk Island", + "NameGerman": "Norfolkinsel", + "NameSlovak": "Norfolk" + }, + { + "Code": "NO", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 164, + "IsEuMember": false, + "Name": "Norsko", + "NameEnglish": "Norway", + "NameGerman": "Norwegen", + "NameSlovak": "Nórsko" + }, + { + "Code": "MP", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 165, + "IsEuMember": false, + "Name": "Severní Mariany", + "NameEnglish": "Northern Mariana Islands (the)", + "NameGerman": "Nördliche Marianen", + "NameSlovak": "Severné Mariány" + }, + { + "Code": "UM", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 166, + "IsEuMember": false, + "Name": "Menší odlehlé ostrovy USA", + "NameEnglish": "United States Minor Outlying Islands (the)", + "NameGerman": "Kleinere amerikanische Überseeinseln", + "NameSlovak": "Menšie odľahlé ostrovy USA" + }, + { + "Code": "FM", + "CurrencyId": 11, + "DateLastChange": "2018-11-07", + "Id": 167, + "IsEuMember": false, + "Name": "Mikronésie", + "NameEnglish": "Micronesia (Federated States of)", + "NameGerman": "Mikronesien", + "NameSlovak": "Mikronézia" + }, + { + "Code": "MH", + "CurrencyId": 11, + "DateLastChange": "1753-01-01", + "Id": 168, + "IsEuMember": false, + "Name": "Marshallovy ostrovy", + "NameEnglish": "Marshall Islands (the)", + "NameGerman": "Marshallinseln", + "NameSlovak": "Marshallove ostrovy" + }, + { + "Code": "PW", + "CurrencyId": 11, + "DateLastChange": "1753-01-01", + "Id": 169, + "IsEuMember": false, + "Name": "Palau", + "NameEnglish": "Palau", + "NameGerman": "Palau", + "NameSlovak": "Palau" + }, + { + "Code": "PK", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 170, + "IsEuMember": false, + "Name": "Pákistán", + "NameEnglish": "Pakistan", + "NameGerman": "Pakistan", + "NameSlovak": "Pakistan" + }, + { + "Code": "PA", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 171, + "IsEuMember": false, + "Name": "Panama", + "NameEnglish": "Panama", + "NameGerman": "Panama", + "NameSlovak": "Panama" + }, + { + "Code": "PG", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 172, + "IsEuMember": false, + "Name": "Papua Nová Guinea", + "NameEnglish": "Papua New Guinea", + "NameGerman": "Papua-Neuguinea", + "NameSlovak": "Papua Nová Guinea" + }, + { + "Code": "PY", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 173, + "IsEuMember": false, + "Name": "Paraguay", + "NameEnglish": "Paraguay", + "NameGerman": "Paraguay", + "NameSlovak": "Paraguay" + }, + { + "Code": "PE", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 174, + "IsEuMember": false, + "Name": "Peru", + "NameEnglish": "Peru", + "NameGerman": "Peru", + "NameSlovak": "Peru" + }, + { + "Code": "PH", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 175, + "IsEuMember": false, + "Name": "Filipíny", + "NameEnglish": "Philippines (the)", + "NameGerman": "Philippinen", + "NameSlovak": "Filipíny" + }, + { + "Code": "PN", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 176, + "IsEuMember": false, + "Name": "Pitcairn", + "NameEnglish": "Pitcairn", + "NameGerman": "Pitcairn", + "NameSlovak": "Pitcairn (ostrov)" + }, + { + "Code": "PL", + "CurrencyId": 8, + "DateLastChange": "1753-01-01", + "Id": 177, + "IsEuMember": true, + "Name": "Polsko", + "NameEnglish": "Poland", + "NameGerman": "Polen", + "NameSlovak": "Poľsko" + }, + { + "Code": "PT", + "CurrencyId": 2, + "DateLastChange": "1753-01-01", + "Id": 178, + "IsEuMember": true, + "Name": "Portugalsko", + "NameEnglish": "Portugal", + "NameGerman": "Portugal", + "NameSlovak": "Portugalsko" + }, + { + "Code": "GW", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 179, + "IsEuMember": false, + "Name": "Guinea-Bissau", + "NameEnglish": "Guinea-Bissau", + "NameGerman": "Guinea-Bissau", + "NameSlovak": "Guinea-Bissau" + }, + { + "Code": "TL", + "CurrencyId": 11, + "DateLastChange": "1753-01-01", + "Id": 180, + "IsEuMember": false, + "Name": "Východní Timor", + "NameEnglish": "Timor-Leste", + "NameGerman": "Osttimor", + "NameSlovak": "Východný Timor" + }, + { + "Code": "PR", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 181, + "IsEuMember": false, + "Name": "Portoriko", + "NameEnglish": "Puerto Rico", + "NameGerman": "Puerto Rico", + "NameSlovak": "Portoriko" + }, + { + "Code": "QA", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 182, + "IsEuMember": false, + "Name": "Katar", + "NameEnglish": "Qatar", + "NameGerman": "Katar", + "NameSlovak": "Katar" + }, + { + "Code": "RE", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 183, + "IsEuMember": false, + "Name": "Réunion", + "NameEnglish": "Réunion", + "NameGerman": "Réunion", + "NameSlovak": "Réunion" + }, + { + "Code": "RO", + "CurrencyId": 9, + "DateLastChange": "1753-01-01", + "Id": 184, + "IsEuMember": true, + "Name": "Rumunsko", + "NameEnglish": "Romania", + "NameGerman": "Rumänien", + "NameSlovak": "Rumunsko" + }, + { + "Code": "RU", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 185, + "IsEuMember": false, + "Name": "Rusko", + "NameEnglish": "Russian Federation (the)", + "NameGerman": "Russland", + "NameSlovak": "Rusko" + }, + { + "Code": "RW", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 186, + "IsEuMember": false, + "Name": "Rwanda", + "NameEnglish": "Rwanda", + "NameGerman": "Ruanda", + "NameSlovak": "Rwanda" + }, + { + "Code": "BL", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 187, + "IsEuMember": false, + "Name": "Svatý Bartoloměj", + "NameEnglish": "Saint Barthélemy", + "NameGerman": "Saint-Barthélemy", + "NameSlovak": "Svätý Bartolomej" + }, + { + "Code": "SH", + "CurrencyId": 1, + "DateLastChange": "2016-07-26", + "Id": 188, + "IsEuMember": false, + "Name": "Svatá Helena", + "NameEnglish": "Saint Helena, Ascension and Tristan da Cunha", + "NameGerman": "St. Helena", + "NameSlovak": "Svätá Helena" + }, + { + "Code": "KN", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 189, + "IsEuMember": false, + "Name": "Svatý Kryštof a Nevis", + "NameEnglish": "Saint Kitts and Nevis", + "NameGerman": "St. Kitts und Nevis", + "NameSlovak": "Svätý Krištof a Nevis" + }, + { + "Code": "AI", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 190, + "IsEuMember": false, + "Name": "Anguilla", + "NameEnglish": "Anguilla", + "NameGerman": "Anguilla", + "NameSlovak": "Anguilla" + }, + { + "Code": "LC", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 191, + "IsEuMember": false, + "Name": "Svatá Lucie", + "NameEnglish": "Saint Lucia", + "NameGerman": "St. Lucia", + "NameSlovak": "Svätá Lucia" + }, + { + "Code": "MF", + "CurrencyId": 1, + "DateLastChange": "2018-11-07", + "Id": 192, + "IsEuMember": false, + "Name": "Svatý Martin (FR)", + "NameEnglish": "Saint Martin (French part)", + "NameGerman": "Saint-Martin (französischer Teil)", + "NameSlovak": "Svätý Martin (FR)" + }, + { + "Code": "PM", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 193, + "IsEuMember": false, + "Name": "Saint Pierre a Miquelon", + "NameEnglish": "Saint Pierre and Miquelon", + "NameGerman": "Saint-Pierre und Miquelon", + "NameSlovak": "Saint Pierre a Miquelon" + }, + { + "Code": "VC", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 194, + "IsEuMember": false, + "Name": "Svatý Vincenc a Grenadiny", + "NameEnglish": "Saint Vincent and the Grenadines", + "NameGerman": "St. Vincent und die Grenadinen", + "NameSlovak": "Svätý Vincent a Grenadíny" + }, + { + "Code": "SM", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 195, + "IsEuMember": false, + "Name": "San Marino", + "NameEnglish": "San Marino", + "NameGerman": "San Marino", + "NameSlovak": "San Maríno" + }, + { + "Code": "ST", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 196, + "IsEuMember": false, + "Name": "Svatý Tomáš a Princův ostrov", + "NameEnglish": "Sao Tome and Principe", + "NameGerman": "São Tomé und Príncipe", + "NameSlovak": "Svätý Tomáš a Princov ostrov" + }, + { + "Code": "SA", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 197, + "IsEuMember": false, + "Name": "Saúdská Arábie", + "NameEnglish": "Saudi Arabia", + "NameGerman": "Saudi-Arabien", + "NameSlovak": "Saudská Arábia" + }, + { + "Code": "SN", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 198, + "IsEuMember": false, + "Name": "Senegal", + "NameEnglish": "Senegal", + "NameGerman": "Senegal", + "NameSlovak": "Senegal" + }, + { + "Code": "RS", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 199, + "IsEuMember": false, + "Name": "Srbsko", + "NameEnglish": "Serbia", + "NameGerman": "Serbien", + "NameSlovak": "Srbsko" + }, + { + "Code": "SC", + "CurrencyId": 1, + "DateLastChange": "1753-01-01", + "Id": 200, + "IsEuMember": false, + "Name": "Seychely", + "NameEnglish": "Seychelles", + "NameGerman": "Seychellen", + "NameSlovak": "Seychely" + } + ], + "TotalItems": 253, + "TotalPages": 2 + }, + "ErrorCode": 0, + "IsSuccess": true, + "Message": "", + "StatusCode": 200 +} \ No newline at end of file From 483f71ce0be83d2fbf362b38cf026f3935bc8060 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 18 Nov 2024 20:04:22 +0100 Subject: [PATCH 09/32] countries in yaml --- rowers/idoklad_countries.yaml | 1808 +++++++++++++++++++++++++++++++++ 1 file changed, 1808 insertions(+) create mode 100644 rowers/idoklad_countries.yaml diff --git a/rowers/idoklad_countries.yaml b/rowers/idoklad_countries.yaml new file mode 100644 index 00000000..4ba88406 --- /dev/null +++ b/rowers/idoklad_countries.yaml @@ -0,0 +1,1808 @@ +Data: + Items: + - Code: SK + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 1 + IsEuMember: true + Name: Slovensko + NameEnglish: Slovakia + NameGerman: Slowakei + NameSlovak: Slovensko + - Code: CZ + CurrencyId: 1 + DateLastChange: '2022-10-25' + Id: 2 + IsEuMember: true + Name: Česká republika + NameEnglish: Czechia + NameGerman: Tschechische Republik + NameSlovak: Česká republika + - Code: AF + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 3 + IsEuMember: false + Name: Afghánistán + NameEnglish: Afghanistan + NameGerman: Afghanistan + NameSlovak: Afganistan + - Code: AL + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 4 + IsEuMember: false + Name: Albánie + NameEnglish: Albania + NameGerman: Albanien + NameSlovak: Albánsko + - Code: AQ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 5 + IsEuMember: false + Name: Antarktida + NameEnglish: Antarctica + NameGerman: Antarktis + NameSlovak: Antarktída + - Code: DZ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 6 + IsEuMember: false + Name: Alžírsko + NameEnglish: Algeria + NameGerman: Algerien + NameSlovak: Alžírsko + - Code: AS + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 7 + IsEuMember: false + Name: Americká Samoa + NameEnglish: American Samoa + NameGerman: Amerikanisch-Samoa + NameSlovak: Americká Samoa + - Code: AD + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 8 + IsEuMember: false + Name: Andorra + NameEnglish: Andorra + NameGerman: Andorra + NameSlovak: Andorra + - Code: AO + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 9 + IsEuMember: false + Name: Angola + NameEnglish: Angola + NameGerman: Angola + NameSlovak: Angola + - Code: AG + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 10 + IsEuMember: false + Name: Antigua a Barbuda + NameEnglish: Antigua and Barbuda + NameGerman: Antigua und Barbuda + NameSlovak: Antigua a Barbuda + - Code: AZ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 11 + IsEuMember: false + Name: Ázerbájdžán + NameEnglish: Azerbaijan + NameGerman: Aserbaidschan + NameSlovak: Azerbajdžan + - Code: AR + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 12 + IsEuMember: false + Name: Argentina + NameEnglish: Argentina + NameGerman: Argentinien + NameSlovak: Argentína + - Code: AU + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 13 + IsEuMember: false + Name: Austrálie + NameEnglish: Australia + NameGerman: Australien + NameSlovak: Austrália + - Code: AT + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 14 + IsEuMember: true + Name: Rakousko + NameEnglish: Austria + NameGerman: Österreich + NameSlovak: Rakúsko + - Code: BS + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 15 + IsEuMember: false + Name: Bahamy + NameEnglish: Bahamas (The) + NameGerman: Bahamas + NameSlovak: Bahamy + - Code: BH + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 16 + IsEuMember: false + Name: Bahrajn + NameEnglish: Bahrain + NameGerman: Bahrain + NameSlovak: Bahrajn + - Code: BD + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 17 + IsEuMember: false + Name: Bangladéš + NameEnglish: Bangladesh + NameGerman: Bangladesch + NameSlovak: Bangladéš + - Code: AM + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 18 + IsEuMember: false + Name: Arménie + NameEnglish: Armenia + NameGerman: Armenien + NameSlovak: Arménsko + - Code: BB + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 19 + IsEuMember: false + Name: Barbados + NameEnglish: Barbados + NameGerman: Barbados + NameSlovak: Barbados + - Code: BE + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 20 + IsEuMember: true + Name: Belgie + NameEnglish: Belgium + NameGerman: 'Belgien ' + NameSlovak: Belgicko + - Code: BM + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 21 + IsEuMember: false + Name: Bermudy + NameEnglish: Bermuda + NameGerman: Bermuda + NameSlovak: Bermudy + - Code: BT + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 22 + IsEuMember: false + Name: Bhútán + NameEnglish: Bhutan + NameGerman: Bhutan + NameSlovak: Bhután + - Code: BO + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 23 + IsEuMember: false + Name: Bolívie + NameEnglish: Bolivia (Plurinational State of) + NameGerman: Bolivien + NameSlovak: Bolívia + - Code: BA + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 24 + IsEuMember: false + Name: Bosna a Hercegovina + NameEnglish: Bosnia and Herzegovina + NameGerman: ' Bosnien und Herzegowina' + NameSlovak: Bosna a Hercegovina + - Code: BW + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 25 + IsEuMember: false + Name: Botswana + NameEnglish: Botswana + NameGerman: Botswana + NameSlovak: Botswana + - Code: BV + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 26 + IsEuMember: false + Name: Bouvetův ostrov + NameEnglish: Bouvet Island + NameGerman: Bouvetinsel + NameSlovak: Bouvetov ostrov + - Code: BR + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 27 + IsEuMember: false + Name: Brazílie + NameEnglish: Brazil + NameGerman: Brasilien + NameSlovak: Brazília + - Code: BZ + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 28 + IsEuMember: false + Name: Belize + NameEnglish: Belize + NameGerman: Belize + NameSlovak: Belize + - Code: IO + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 29 + IsEuMember: false + Name: Britské indickooceánské území + NameEnglish: "British Indian Ocean Territory (the)\r\n" + NameGerman: Britisches Territorium im Indischen Ozean + NameSlovak: Britské indickooceánske územie + - Code: SB + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 30 + IsEuMember: false + Name: Šalomounovy ostrovy + NameEnglish: Solomon Islands + NameGerman: Salomonen + NameSlovak: Šalamúnove ostrovy + - Code: VG + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 31 + IsEuMember: false + Name: Britské Panenské ostrovy + NameEnglish: Virgin Islands (British) + NameGerman: Britische Jungferninseln + NameSlovak: Britské Panenské ostrovy + - Code: XK + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 32 + IsEuMember: false + Name: Kosovo + NameEnglish: Republic of Kosovo + NameGerman: Kosovo + NameSlovak: Kosovo + - Code: BN + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 33 + IsEuMember: false + Name: Brunej + NameEnglish: Brunei Darussalam + NameGerman: Brunei + NameSlovak: Brunej + - Code: BG + CurrencyId: 3 + DateLastChange: '1753-01-01' + Id: 34 + IsEuMember: true + Name: Bulharsko + NameEnglish: Bulgaria + NameGerman: Bulgarien + NameSlovak: Bulharsko + - Code: MM + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 35 + IsEuMember: false + Name: Myanmar + NameEnglish: Myanmar + NameGerman: Myanmar + NameSlovak: Mjanmarsko + - Code: BI + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 36 + IsEuMember: false + Name: Burundi + NameEnglish: Burundi + NameGerman: Burundi + NameSlovak: Burundi + - Code: BY + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 37 + IsEuMember: false + Name: Bělorusko + NameEnglish: Belarus + NameGerman: Belarus + NameSlovak: Bielorusko + - Code: KH + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 38 + IsEuMember: false + Name: Kambodža + NameEnglish: Cambodia + NameGerman: Kambodscha + NameSlovak: Kambodža + - Code: CM + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 39 + IsEuMember: false + Name: Kamerun + NameEnglish: Cameroon + NameGerman: Kamerun + NameSlovak: Kamerun + - Code: CA + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 40 + IsEuMember: false + Name: Kanada + NameEnglish: Canada + NameGerman: Kanada + NameSlovak: Kanada + - Code: CV + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 41 + IsEuMember: false + Name: Kapverdy + NameEnglish: Cape Verde + NameGerman: Kap Verde + NameSlovak: Kapverdy + - Code: KY + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 42 + IsEuMember: false + Name: Kajmanské ostrovy + NameEnglish: Cayman Islands (the) + NameGerman: Kaimaninseln + NameSlovak: Kajmanské ostrovy + - Code: CF + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 43 + IsEuMember: false + Name: Středoafrická republika + NameEnglish: Central African Republic (the) + NameGerman: Zentralafrikanische Republik + NameSlovak: Stredoafrická republika + - Code: LK + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 44 + IsEuMember: false + Name: Šrí Lanka + NameEnglish: Sri Lanka + NameGerman: Sri Lanka + NameSlovak: Srí Lanka + - Code: TD + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 45 + IsEuMember: false + Name: Čad + NameEnglish: Chad + NameGerman: Tschad + NameSlovak: Čad + - Code: CL + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 46 + IsEuMember: false + Name: Chile + NameEnglish: Chile + NameGerman: 'Chile ' + NameSlovak: Čile + - Code: CN + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 47 + IsEuMember: false + Name: Čína + NameEnglish: China + NameGerman: China + NameSlovak: Čína + - Code: TW + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 48 + IsEuMember: false + Name: Tchaj-wan + NameEnglish: Taiwan (Province of China) + NameGerman: Taiwan + NameSlovak: Taiwan + - Code: CX + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 49 + IsEuMember: false + Name: Vánoční ostrov + NameEnglish: Christmas Island + NameGerman: Weihnachtsinsel + NameSlovak: Vianočný ostrov + - Code: CC + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 50 + IsEuMember: false + Name: Kokosové (Keelingovy) ostrovy + NameEnglish: Cocos (Keeling) Islands (the) + NameGerman: Kokosinseln (Keelinginseln) + NameSlovak: Kokosové (Keelingove) ostrovy + - Code: CO + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 51 + IsEuMember: false + Name: Kolumbie + NameEnglish: Colombia + NameGerman: Kolumbien + NameSlovak: Kolumbia + - Code: KM + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 52 + IsEuMember: false + Name: Komory + NameEnglish: Comoros (the) + NameGerman: Komoren + NameSlovak: Komory + - Code: YT + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 53 + IsEuMember: false + Name: Mayotte + NameEnglish: Mayotte + NameGerman: Mayotte + NameSlovak: Mayotte + - Code: CG + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 54 + IsEuMember: false + Name: Konžská republika + NameEnglish: Congo (the) + NameGerman: Republik Kongo + NameSlovak: Konžská republika + - Code: CD + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 55 + IsEuMember: false + Name: Demokratická republika Kongo + NameEnglish: Congo (the Democratic Republic of the) + NameGerman: Demokratische Republik Kongo + NameSlovak: Konžská demokratická republika + - Code: CK + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 56 + IsEuMember: false + Name: Cookovy ostrovy + NameEnglish: Cook Islands (the) + NameGerman: Cookinseln + NameSlovak: Cookove ostrovy + - Code: CR + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 57 + IsEuMember: false + Name: Kostarika + NameEnglish: Costa Rica + NameGerman: Costa Rica + NameSlovak: Kostarika + - Code: HR + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 58 + IsEuMember: true + Name: Chorvatsko + NameEnglish: Croatia + NameGerman: Kroatien + NameSlovak: Chorvátsko + - Code: CU + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 59 + IsEuMember: false + Name: Kuba + NameEnglish: Cuba + NameGerman: Kuba + NameSlovak: Kuba + - Code: CY + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 60 + IsEuMember: true + Name: Kypr + NameEnglish: Cyprus + NameGerman: Zypern + NameSlovak: Cyprus + - Code: BJ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 61 + IsEuMember: false + Name: Benin + NameEnglish: Benin + NameGerman: Benin + NameSlovak: Benin + - Code: DK + CurrencyId: 4 + DateLastChange: '1753-01-01' + Id: 62 + IsEuMember: true + Name: Dánsko + NameEnglish: Denmark + NameGerman: Dänemark + NameSlovak: Dánsko + - Code: DM + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 63 + IsEuMember: false + Name: Dominika + NameEnglish: Dominica + NameGerman: Dominica + NameSlovak: Dominika + - Code: DO + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 64 + IsEuMember: false + Name: Dominikánská republika + NameEnglish: Dominican Republic (the) + NameGerman: Dominikanische Republik + NameSlovak: Dominikánska republika + - Code: EC + CurrencyId: 11 + DateLastChange: '1753-01-01' + Id: 65 + IsEuMember: false + Name: Ekvádor + NameEnglish: Ecuador + NameGerman: Ecuador + NameSlovak: Ekvádor + - Code: SV + CurrencyId: 11 + DateLastChange: '1753-01-01' + Id: 66 + IsEuMember: false + Name: Salvador + NameEnglish: El Salvador + NameGerman: El Salvador + NameSlovak: Salvador + - Code: GQ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 67 + IsEuMember: false + Name: Rovníková Guinea + NameEnglish: Equatorial Guinea + NameGerman: Äquatorialguinea + NameSlovak: Rovníková Guinea + - Code: ET + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 68 + IsEuMember: false + Name: Etiopie + NameEnglish: Ethiopia + NameGerman: Äthiopien + NameSlovak: Etiópia + - Code: ER + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 69 + IsEuMember: false + Name: Eritrea + NameEnglish: Eritrea + NameGerman: Eritrea + NameSlovak: Eritrejský štát + - Code: EE + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 70 + IsEuMember: true + Name: Estonsko + NameEnglish: Estonia + NameGerman: Estland + NameSlovak: Estónsko + - Code: FO + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 71 + IsEuMember: false + Name: Faerské ostrovy + NameEnglish: Faroe Islands (the) + NameGerman: Färöer + NameSlovak: Faerské ostrovy + - Code: FK + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 72 + IsEuMember: false + Name: Falklandy + NameEnglish: Falkland Islands (the) (Malvinas) + NameGerman: Falklandinseln + NameSlovak: Falklandy + - Code: GS + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 73 + IsEuMember: false + Name: Jižní Georgie a Jižní Sandwichovy ostrovy + NameEnglish: South Georgia and the South Sandwich Islands + NameGerman: Südgeorgien und die Südlichen Sandwichinseln + NameSlovak: Južná Georgia a Južné Sandwichove ostrovy + - Code: FJ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 74 + IsEuMember: false + Name: Fidži + NameEnglish: Fiji + NameGerman: Fidschi + NameSlovak: Fidži + - Code: FI + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 75 + IsEuMember: true + Name: Finsko + NameEnglish: Finland + NameGerman: Finnland + NameSlovak: Fínsko + - Code: AX + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 76 + IsEuMember: false + Name: Alandy + NameEnglish: Åland Islands + NameGerman: Åland + NameSlovak: Alandy + - Code: FR + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 77 + IsEuMember: true + Name: Francie + NameEnglish: France + NameGerman: Frankreich + NameSlovak: Francúzsko + - Code: GF + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 78 + IsEuMember: false + Name: Francouzská Guyana + NameEnglish: French Guiana + NameGerman: Französisch-Guyana + NameSlovak: Francúzska Guyana + - Code: PF + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 79 + IsEuMember: false + Name: Francouzská Polynésie + NameEnglish: French Polynesia + NameGerman: Französisch-Polynesien + NameSlovak: Francúzska Polynézia + - Code: TF + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 80 + IsEuMember: false + Name: Francouzská jižní a antarktická území + NameEnglish: French Southern Territories (the) + NameGerman: Französisch Süd- und Antarktisgebiete + NameSlovak: Francúzske južné a antarktické územia + - Code: DJ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 81 + IsEuMember: false + Name: Džibutsko + NameEnglish: Djibouti + NameGerman: Dschibuti + NameSlovak: Džibutsko + - Code: GA + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 82 + IsEuMember: false + Name: Gabon + NameEnglish: Gabon + NameGerman: Gabon + NameSlovak: Gabon + - Code: GE + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 83 + IsEuMember: false + Name: Gruzie + NameEnglish: Georgia + NameGerman: Georgien + NameSlovak: Gruzínska republika + - Code: GM + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 84 + IsEuMember: false + Name: Gambie + NameEnglish: Gambia (the) + NameGerman: Gambia + NameSlovak: Gambia + - Code: PS + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 85 + IsEuMember: false + Name: Palestina + NameEnglish: Palestine, State of + NameGerman: Palästina + NameSlovak: Palestína + - Code: DE + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 86 + IsEuMember: true + Name: Německo + NameEnglish: Germany + NameGerman: Deutschland + NameSlovak: Nemecko + - Code: GH + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 87 + IsEuMember: false + Name: Ghana + NameEnglish: Ghana + NameGerman: Ghana + NameSlovak: Ghana + - Code: GI + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 88 + IsEuMember: false + Name: Gibraltar + NameEnglish: Gibraltar + NameGerman: Gibraltar + NameSlovak: Gibraltár + - Code: KI + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 89 + IsEuMember: false + Name: Kiribati + NameEnglish: Kiribati + NameGerman: Kiribati + NameSlovak: Kiribati + - Code: GR + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 90 + IsEuMember: true + Name: Řecko + NameEnglish: Greece + NameGerman: Griechenland + NameSlovak: Grécko + - Code: GL + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 91 + IsEuMember: false + Name: Grónsko + NameEnglish: Greenland + NameGerman: Grönland + NameSlovak: Grónsko + - Code: GD + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 92 + IsEuMember: false + Name: Grenada + NameEnglish: Grenada + NameGerman: Grenada + NameSlovak: Grenada + - Code: GP + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 93 + IsEuMember: false + Name: Guadeloupe + NameEnglish: Guadeloupe + NameGerman: Guadeloupe + NameSlovak: Guadeloupe + - Code: GU + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 94 + IsEuMember: false + Name: Guam + NameEnglish: Guam + NameGerman: Guam + NameSlovak: Guam + - Code: GT + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 95 + IsEuMember: false + Name: Guatemala + NameEnglish: Guatemala + NameGerman: Guatemala + NameSlovak: Guatemala + - Code: GN + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 96 + IsEuMember: false + Name: Guinea + NameEnglish: Guinea + NameGerman: Guinea + NameSlovak: Guinea + - Code: GY + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 97 + IsEuMember: false + Name: Guyana + NameEnglish: Guyana + NameGerman: Guyana + NameSlovak: Guyana + - Code: HT + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 98 + IsEuMember: false + Name: Haiti + NameEnglish: Haiti + NameGerman: Haiti + NameSlovak: Haiti + - Code: HM + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 99 + IsEuMember: false + Name: Heardův ostrov a MacDonaldovy ostrovy + NameEnglish: Heard Island and McDonald Islands + NameGerman: Heard und die McDonaldinseln + NameSlovak: Heardov ostrov a Macdonaldove ostrovy + - Code: VA + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 100 + IsEuMember: false + Name: Vatikán + NameEnglish: Holy See (the) + NameGerman: Vatikanstadt + NameSlovak: Vatikán + - Code: HN + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 101 + IsEuMember: false + Name: Honduras + NameEnglish: Honduras + NameGerman: Honduras + NameSlovak: Honduras + - Code: HK + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 102 + IsEuMember: false + Name: Hongkong + NameEnglish: Hong Kong + NameGerman: Hongkong + NameSlovak: Hongkong + - Code: HU + CurrencyId: 5 + DateLastChange: '1753-01-01' + Id: 103 + IsEuMember: true + Name: Maďarsko + NameEnglish: Hungary + NameGerman: Ungarn + NameSlovak: Maďarsko + - Code: IS + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 104 + IsEuMember: false + Name: Island + NameEnglish: Iceland + NameGerman: Island + NameSlovak: Island + - Code: IN + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 105 + IsEuMember: false + Name: Indie + NameEnglish: India + NameGerman: Indien + NameSlovak: India + - Code: ID + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 106 + IsEuMember: false + Name: Indonésie + NameEnglish: Indonesia + NameGerman: Indonesien + NameSlovak: Indonézia + - Code: IR + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 107 + IsEuMember: false + Name: Írán + NameEnglish: Iran (Islamic Republic of) + NameGerman: Iran + NameSlovak: Irán + - Code: IQ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 108 + IsEuMember: false + Name: Irák + NameEnglish: Iraq + NameGerman: Irak + NameSlovak: Irak + - Code: IE + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 109 + IsEuMember: true + Name: Irsko + NameEnglish: Ireland + NameGerman: Irland + NameSlovak: Írsko + - Code: IL + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 110 + IsEuMember: false + Name: Izrael + NameEnglish: Israel + NameGerman: Israel + NameSlovak: Izrael + - Code: IT + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 111 + IsEuMember: true + Name: Itálie + NameEnglish: Italy + NameGerman: Italien + NameSlovak: Taliansko + - Code: CI + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 112 + IsEuMember: false + Name: Pobřeží slonoviny + NameEnglish: Côte d'Ivoire + NameGerman: Côte d'Ivoire + NameSlovak: Pobrežie Slonoviny + - Code: JM + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 113 + IsEuMember: false + Name: Jamajka + NameEnglish: Jamaica + NameGerman: Jamaika + NameSlovak: Jamajka + - Code: JP + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 114 + IsEuMember: false + Name: Japonsko + NameEnglish: Japan + NameGerman: Japan + NameSlovak: Japonsko + - Code: KZ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 115 + IsEuMember: false + Name: Kazachstán + NameEnglish: Kazakhstan + NameGerman: Kasachstan + NameSlovak: Kazachstan + - Code: JO + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 116 + IsEuMember: false + Name: Jordánsko + NameEnglish: Jordan + NameGerman: Jordanien + NameSlovak: Jordánsko + - Code: KE + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 117 + IsEuMember: false + Name: Keňa + NameEnglish: Kenya + NameGerman: Kenia + NameSlovak: Keňa + - Code: KP + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 118 + IsEuMember: false + Name: Korejská lidově demokratická republika + NameEnglish: Korea (the Democratic People's Republic of) + NameGerman: Demokratische Volksrepublik Korea + NameSlovak: Kórejská ľudovodemokratická republika + - Code: KR + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 119 + IsEuMember: false + Name: Korejská republika + NameEnglish: Korea (the Republic of) + NameGerman: Republik Korea + NameSlovak: Kórejská republika + - Code: KW + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 120 + IsEuMember: false + Name: Kuvajt + NameEnglish: Kuwait + NameGerman: Kuwait + NameSlovak: Kuvajt + - Code: KG + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 121 + IsEuMember: false + Name: Kyrgyzstán + NameEnglish: Kyrgyzstan + NameGerman: Kirgisistan + NameSlovak: Kirgizsko + - Code: LA + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 122 + IsEuMember: false + Name: Laos + NameEnglish: Lao People's Democratic Republic (the) + NameGerman: Laos + NameSlovak: Laos + - Code: LB + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 123 + IsEuMember: false + Name: Libanon + NameEnglish: Lebanon + NameGerman: Libanon + NameSlovak: Libanon + - Code: LS + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 124 + IsEuMember: false + Name: Lesotho + NameEnglish: Lesotho + NameGerman: Lesotho + NameSlovak: Lesotho + - Code: LV + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 125 + IsEuMember: true + Name: Lotyšsko + NameEnglish: Latvia + NameGerman: Lettland + NameSlovak: Lotyšsko + - Code: LR + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 126 + IsEuMember: false + Name: Libérie + NameEnglish: Liberia + NameGerman: Liberia + NameSlovak: Libéria + - Code: LY + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 127 + IsEuMember: false + Name: Libye + NameEnglish: Libya + NameGerman: Libyen + NameSlovak: Líbyjský štát + - Code: LI + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 128 + IsEuMember: false + Name: Lichtenštejnsko + NameEnglish: Liechtenstein + NameGerman: Liechtenstein + NameSlovak: Lichtenštajnsko + - Code: LT + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 129 + IsEuMember: true + Name: Litva + NameEnglish: Lithuania + NameGerman: Litauen + NameSlovak: Litva + - Code: LU + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 130 + IsEuMember: true + Name: Lucembursko + NameEnglish: Luxembourg + NameGerman: Luxemburg + NameSlovak: Luxembursko + - Code: MO + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 131 + IsEuMember: false + Name: Macao + NameEnglish: Macao + NameGerman: Macao + NameSlovak: Macao + - Code: MG + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 132 + IsEuMember: false + Name: Madagaskar + NameEnglish: Madagascar + NameGerman: Madagaskar + NameSlovak: Madagaskar + - Code: MW + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 133 + IsEuMember: false + Name: Malawi + NameEnglish: Malawi + NameGerman: Malawi + NameSlovak: Malawi + - Code: MY + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 134 + IsEuMember: false + Name: Malajsie + NameEnglish: Malaysia + NameGerman: Malaysia + NameSlovak: Malajzia + - Code: MV + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 135 + IsEuMember: false + Name: Maledivy + NameEnglish: Maldives + NameGerman: Malediven + NameSlovak: Maledivy + - Code: ML + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 136 + IsEuMember: false + Name: Mali + NameEnglish: Mali + NameGerman: Mali + NameSlovak: Mali + - Code: MT + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 137 + IsEuMember: true + Name: Malta + NameEnglish: Malta + NameGerman: Malta + NameSlovak: Malta + - Code: MQ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 138 + IsEuMember: false + Name: Martinik + NameEnglish: Martinique + NameGerman: Martinique + NameSlovak: Martinik + - Code: MR + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 139 + IsEuMember: false + Name: Mauritánie + NameEnglish: Mauritania + NameGerman: Mauretanien + NameSlovak: Mauritánia + - Code: MU + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 140 + IsEuMember: false + Name: Mauricius + NameEnglish: Mauritius + NameGerman: Mauritius + NameSlovak: Mauricius + - Code: MX + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 141 + IsEuMember: false + Name: Mexiko + NameEnglish: Mexico + NameGerman: Mexiko + NameSlovak: Mexiko + - Code: MC + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 142 + IsEuMember: false + Name: Monako + NameEnglish: Monaco + NameGerman: Monaco + NameSlovak: Monako + - Code: MN + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 143 + IsEuMember: false + Name: Mongolsko + NameEnglish: Mongolia + NameGerman: Mongolei + NameSlovak: Mongolská republika + - Code: MD + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 144 + IsEuMember: false + Name: Moldavsko + NameEnglish: Moldova (the Republic of) + NameGerman: Moldau + NameSlovak: Moldavsko + - Code: ME + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 145 + IsEuMember: false + Name: Černá Hora + NameEnglish: Montenegro + NameGerman: Montenegro + NameSlovak: Čierna Hora + - Code: MS + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 146 + IsEuMember: false + Name: Montserrat + NameEnglish: Montserrat + NameGerman: Montserrat + NameSlovak: Montserrat + - Code: MA + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 147 + IsEuMember: false + Name: Maroko + NameEnglish: Morocco + NameGerman: Marokko + NameSlovak: Maroko + - Code: MZ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 148 + IsEuMember: false + Name: Mosambik + NameEnglish: Mozambique + NameGerman: Mosambik + NameSlovak: Mozambik + - Code: OM + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 149 + IsEuMember: false + Name: Omán + NameEnglish: Oman + NameGerman: Oman + NameSlovak: Omán + - Code: NA + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 150 + IsEuMember: false + Name: Namibie + NameEnglish: Namibia + NameGerman: Namibia + NameSlovak: Namíbia + - Code: NR + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 151 + IsEuMember: false + Name: Nauru + NameEnglish: Nauru + NameGerman: Nauru + NameSlovak: Nauru + - Code: NP + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 152 + IsEuMember: false + Name: Nepál + NameEnglish: Nepal + NameGerman: 'Nepal ' + NameSlovak: Nepál + - Code: NL + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 153 + IsEuMember: true + Name: Nizozemsko + NameEnglish: Netherlands (the) + NameGerman: Niederlande + NameSlovak: Holandsko + - Code: AN + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 154 + IsEuMember: false + Name: Nizozemské Antily + NameEnglish: Netherlands Antilles + NameGerman: Niederländische Antillen + NameSlovak: Holandské Antily + - Code: AW + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 155 + IsEuMember: false + Name: Aruba + NameEnglish: Aruba + NameGerman: Aruba + NameSlovak: Aruba + - Code: NC + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 156 + IsEuMember: false + Name: Nová Kaledonie + NameEnglish: New Caledonia + NameGerman: Neukaledonien + NameSlovak: Nová Kaledónia + - Code: VU + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 157 + IsEuMember: false + Name: Vanuatu + NameEnglish: Vanuatu + NameGerman: Vanuatu + NameSlovak: Vanuatu + - Code: NZ + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 158 + IsEuMember: false + Name: Nový Zéland + NameEnglish: New Zealand + NameGerman: Neuseeland + NameSlovak: Nový Zéland + - Code: NI + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 159 + IsEuMember: false + Name: Nikaragua + NameEnglish: Nicaragua + NameGerman: Nicaragua + NameSlovak: Nikaragua + - Code: NE + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 160 + IsEuMember: false + Name: Niger + NameEnglish: Niger (the) + NameGerman: Niger + NameSlovak: Niger + - Code: NG + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 161 + IsEuMember: false + Name: Nigérie + NameEnglish: Nigeria + NameGerman: Nigeria + NameSlovak: Nigéria + - Code: NU + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 162 + IsEuMember: false + Name: Niue + NameEnglish: Niue + NameGerman: Niue + NameSlovak: Niue + - Code: NF + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 163 + IsEuMember: false + Name: Norfolk + NameEnglish: Norfolk Island + NameGerman: Norfolkinsel + NameSlovak: Norfolk + - Code: 'NO' + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 164 + IsEuMember: false + Name: Norsko + NameEnglish: Norway + NameGerman: Norwegen + NameSlovak: Nórsko + - Code: MP + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 165 + IsEuMember: false + Name: Severní Mariany + NameEnglish: Northern Mariana Islands (the) + NameGerman: Nördliche Marianen + NameSlovak: Severné Mariány + - Code: UM + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 166 + IsEuMember: false + Name: Menší odlehlé ostrovy USA + NameEnglish: United States Minor Outlying Islands (the) + NameGerman: Kleinere amerikanische Überseeinseln + NameSlovak: Menšie odľahlé ostrovy USA + - Code: FM + CurrencyId: 11 + DateLastChange: '2018-11-07' + Id: 167 + IsEuMember: false + Name: Mikronésie + NameEnglish: Micronesia (Federated States of) + NameGerman: Mikronesien + NameSlovak: Mikronézia + - Code: MH + CurrencyId: 11 + DateLastChange: '1753-01-01' + Id: 168 + IsEuMember: false + Name: Marshallovy ostrovy + NameEnglish: Marshall Islands (the) + NameGerman: Marshallinseln + NameSlovak: Marshallove ostrovy + - Code: PW + CurrencyId: 11 + DateLastChange: '1753-01-01' + Id: 169 + IsEuMember: false + Name: Palau + NameEnglish: Palau + NameGerman: Palau + NameSlovak: Palau + - Code: PK + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 170 + IsEuMember: false + Name: Pákistán + NameEnglish: Pakistan + NameGerman: Pakistan + NameSlovak: Pakistan + - Code: PA + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 171 + IsEuMember: false + Name: Panama + NameEnglish: Panama + NameGerman: Panama + NameSlovak: Panama + - Code: PG + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 172 + IsEuMember: false + Name: Papua Nová Guinea + NameEnglish: Papua New Guinea + NameGerman: Papua-Neuguinea + NameSlovak: Papua Nová Guinea + - Code: PY + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 173 + IsEuMember: false + Name: Paraguay + NameEnglish: Paraguay + NameGerman: Paraguay + NameSlovak: Paraguay + - Code: PE + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 174 + IsEuMember: false + Name: Peru + NameEnglish: Peru + NameGerman: Peru + NameSlovak: Peru + - Code: PH + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 175 + IsEuMember: false + Name: Filipíny + NameEnglish: Philippines (the) + NameGerman: Philippinen + NameSlovak: Filipíny + - Code: PN + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 176 + IsEuMember: false + Name: Pitcairn + NameEnglish: Pitcairn + NameGerman: Pitcairn + NameSlovak: Pitcairn (ostrov) + - Code: PL + CurrencyId: 8 + DateLastChange: '1753-01-01' + Id: 177 + IsEuMember: true + Name: Polsko + NameEnglish: Poland + NameGerman: Polen + NameSlovak: Poľsko + - Code: PT + CurrencyId: 2 + DateLastChange: '1753-01-01' + Id: 178 + IsEuMember: true + Name: Portugalsko + NameEnglish: Portugal + NameGerman: Portugal + NameSlovak: Portugalsko + - Code: GW + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 179 + IsEuMember: false + Name: Guinea-Bissau + NameEnglish: Guinea-Bissau + NameGerman: Guinea-Bissau + NameSlovak: Guinea-Bissau + - Code: TL + CurrencyId: 11 + DateLastChange: '1753-01-01' + Id: 180 + IsEuMember: false + Name: Východní Timor + NameEnglish: Timor-Leste + NameGerman: Osttimor + NameSlovak: Východný Timor + - Code: PR + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 181 + IsEuMember: false + Name: Portoriko + NameEnglish: Puerto Rico + NameGerman: Puerto Rico + NameSlovak: Portoriko + - Code: QA + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 182 + IsEuMember: false + Name: Katar + NameEnglish: Qatar + NameGerman: Katar + NameSlovak: Katar + - Code: RE + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 183 + IsEuMember: false + Name: Réunion + NameEnglish: Réunion + NameGerman: Réunion + NameSlovak: Réunion + - Code: RO + CurrencyId: 9 + DateLastChange: '1753-01-01' + Id: 184 + IsEuMember: true + Name: Rumunsko + NameEnglish: Romania + NameGerman: Rumänien + NameSlovak: Rumunsko + - Code: RU + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 185 + IsEuMember: false + Name: Rusko + NameEnglish: Russian Federation (the) + NameGerman: Russland + NameSlovak: Rusko + - Code: RW + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 186 + IsEuMember: false + Name: Rwanda + NameEnglish: Rwanda + NameGerman: Ruanda + NameSlovak: Rwanda + - Code: BL + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 187 + IsEuMember: false + Name: Svatý Bartoloměj + NameEnglish: Saint Barthélemy + NameGerman: Saint-Barthélemy + NameSlovak: Svätý Bartolomej + - Code: SH + CurrencyId: 1 + DateLastChange: '2016-07-26' + Id: 188 + IsEuMember: false + Name: Svatá Helena + NameEnglish: Saint Helena, Ascension and Tristan da Cunha + NameGerman: St. Helena + NameSlovak: Svätá Helena + - Code: KN + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 189 + IsEuMember: false + Name: Svatý Kryštof a Nevis + NameEnglish: Saint Kitts and Nevis + NameGerman: St. Kitts und Nevis + NameSlovak: Svätý Krištof a Nevis + - Code: AI + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 190 + IsEuMember: false + Name: Anguilla + NameEnglish: Anguilla + NameGerman: Anguilla + NameSlovak: Anguilla + - Code: LC + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 191 + IsEuMember: false + Name: Svatá Lucie + NameEnglish: Saint Lucia + NameGerman: St. Lucia + NameSlovak: Svätá Lucia + - Code: MF + CurrencyId: 1 + DateLastChange: '2018-11-07' + Id: 192 + IsEuMember: false + Name: Svatý Martin (FR) + NameEnglish: Saint Martin (French part) + NameGerman: Saint-Martin (französischer Teil) + NameSlovak: Svätý Martin (FR) + - Code: PM + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 193 + IsEuMember: false + Name: Saint Pierre a Miquelon + NameEnglish: Saint Pierre and Miquelon + NameGerman: Saint-Pierre und Miquelon + NameSlovak: Saint Pierre a Miquelon + - Code: VC + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 194 + IsEuMember: false + Name: Svatý Vincenc a Grenadiny + NameEnglish: Saint Vincent and the Grenadines + NameGerman: St. Vincent und die Grenadinen + NameSlovak: Svätý Vincent a Grenadíny + - Code: SM + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 195 + IsEuMember: false + Name: San Marino + NameEnglish: San Marino + NameGerman: San Marino + NameSlovak: San Maríno + - Code: ST + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 196 + IsEuMember: false + Name: Svatý Tomáš a Princův ostrov + NameEnglish: Sao Tome and Principe + NameGerman: São Tomé und Príncipe + NameSlovak: Svätý Tomáš a Princov ostrov + - Code: SA + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 197 + IsEuMember: false + Name: Saúdská Arábie + NameEnglish: Saudi Arabia + NameGerman: Saudi-Arabien + NameSlovak: Saudská Arábia + - Code: SN + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 198 + IsEuMember: false + Name: Senegal + NameEnglish: Senegal + NameGerman: Senegal + NameSlovak: Senegal + - Code: RS + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 199 + IsEuMember: false + Name: Srbsko + NameEnglish: Serbia + NameGerman: Serbien + NameSlovak: Srbsko + - Code: SC + CurrencyId: 1 + DateLastChange: '1753-01-01' + Id: 200 + IsEuMember: false + Name: Seychely + NameEnglish: Seychelles + NameGerman: Seychellen + NameSlovak: Seychely + TotalItems: 253 + TotalPages: 2 +ErrorCode: 0 +IsSuccess: true +Message: '' +StatusCode: 200 From 79b682677ad200050cdc7b2c77d9c2bcf5194001 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 18 Nov 2024 20:04:33 +0100 Subject: [PATCH 10/32] reading yaml --- rowers/idoklad.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rowers/idoklad.py b/rowers/idoklad.py index 6c04c45a..d2199c06 100644 --- a/rowers/idoklad.py +++ b/rowers/idoklad.py @@ -1,5 +1,5 @@ import requests -import json +import json, yaml from requests.auth import HTTPBasicAuth import urllib.parse from rowers.utils import dologging @@ -14,7 +14,9 @@ contacts_url = 'https://api.idoklad.cz/v3/Contacts' from rowers.models import iDokladToken -idoklad_countries = json.loads(open('rowers/idoklad_countries.json').read())["Data"]["Items"] +#idoklad_countries = json.loads(open('rowers/idoklad_countries.json').read())["Data"]["Items"] +with open('rowers/idoklad_countries.yaml') as f: + idoklad_countries = yaml.load(f, Loader=yaml.FullLoader)["Data"]["Items"] def get_country_id(code): for c in idoklad_countries: From 615a3fc689b6fde8a93475494b7d4384974a3d0f Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 18 Nov 2024 22:28:55 +0100 Subject: [PATCH 11/32] invoice created, email sending fails --- rowers/idoklad.py | 89 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 12 deletions(-) diff --git a/rowers/idoklad.py b/rowers/idoklad.py index d2199c06..1da50022 100644 --- a/rowers/idoklad.py +++ b/rowers/idoklad.py @@ -11,6 +11,8 @@ from rowsandall_app.settings import ( ) contacts_url = 'https://api.idoklad.cz/v3/Contacts' +invoice_url = 'https://api.idoklad.cz/v3/IssuedInvoices' +email_url = 'https://api.idoklad.cz/v3/Mails/IssuedInvoice/Send' from rowers.models import iDokladToken @@ -51,21 +53,12 @@ def idoklad_token(): token = response.json() token['updated_at'] = timezone.now() token = iDokladToken.objects.filter(id=1).update(**token) - return token + return iDokladToken.objects.get(id=1) else: return None return token -def prepare_invoice(): - token = idoklad_token() - if token is None: - return None - - data = { - 'templateId': 1, - } - def get_contacts(rower): token = idoklad_token() if token is None: @@ -85,8 +78,6 @@ def get_contacts(rower): return None - dologging('idoklad.log','Status Code '+json.dumps(res.json())+'\n') - data = res.json()['Data']['Items'] if len(data) >= 1: @@ -134,4 +125,78 @@ def create_contact(rower): return id +def create_invoice(rower, amount, braintreeid, dosend=True, contact_id=None, name=None): + t = idoklad_token() + if t is None: + return None + + if not contact_id: + contact_id = get_contacts(rower) + if not name: + name = 'Rowsandall Subscription '+str(braintreeid) + + if not contact_id: + return 0 + + token = idoklad_token() + if token is None: + return None + + dologging('idoklad.log','Creating idoklad invoice for '+str(rower.user.email)+'\n') + + headers = { + 'Authorization': 'Bearer {t}'.format(t=token.access_token), + } + + res = requests.get(invoice_url+'/Default', headers=headers) + + post_data = res.json()['Data'] + post_data['DateOfPayment'] = timezone.now().strftime('%Y-%m-%d') + post_data['Description'] = name + post_data['Items'][0]['Name'] = name + post_data['Items'][0]['UnitPrice'] = amount + post_data['PartnerId'] = contact_id + post_data['ItemsTextPrefix'] = 'We invoice you for '+str(name)+' in the amount of '+str(amount)+' EUR.' + post_data['ItemsTextSuffix'] = 'This invoice was already paid. Please do not pay it again.' + post_data['Items'][0]['VatRate'] = 0.0 + post_data['Items'][0]['VatRateType'] = 2 + post_data['Items'][0]['VatCodeId'] = 3 + post_data['CurrencyId'] = 2 + post_data['ReportLanguage'] = 3 + post_data.pop('ExchangeRate', None) + + + res = requests.post(invoice_url, json=post_data, headers=headers) + dologging('idoklad.log','Invoice Created - status code '+str(res.status_code)+'\n') + + if res.status_code not in [200, 201]: + dologging('idoklad.log','Invoice Created - reason '+str(res.reason)+'\n') + return 0 + + id = res.json()['Data']['Id'] + + if dosend: + url = invoice_url+'/'+str(id)+'/Send' + print(url) + data = { + 'AttachmentIds': [id], + 'DocumentId': braintreeid, + 'EmailBody': 'Dear customer, we are sending you the invoice for your subscription. Please do not hesitate to contact us if you have any questions. Best regards, Rowsandall Team', + 'EmailSubject': 'Rowsandall Subscription Invoice', + 'Method': 1, + 'ReportLanguage': 3, + 'SendToSelf': True, + } + + print(data) + print(email_url) + + res = requests.post(email_url, json=data, headers=headers) + + dologging('idoklad.log','Invoice Sent - status code '+str(res.status_code)+'\n') + if res.status_code not in [200, 201]: + dologging('idoklad.log','Invoice Sent - reason '+str(res.reason)+'\n') + + return id + From 7a3fa8fe307f8692f97f87d8cb365f995678622e Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 19 Nov 2024 15:49:44 +0100 Subject: [PATCH 12/32] passing tests --- rowers/braintreestuff.py | 30 ++++++++-------- rowers/idoklad.py | 22 ++++++------ rowers/tests/mocks.py | 49 ++++++++++++++++++++++++++ rowers/tests/test_braintree.py | 7 ++-- rowers/tests/test_payments.py | 2 +- rowers/tests/testdata/testdata.tcx.gz | Bin 4001 -> 4000 bytes 6 files changed, 82 insertions(+), 28 deletions(-) diff --git a/rowers/braintreestuff.py b/rowers/braintreestuff.py index 7cb162d1..df39ecd6 100644 --- a/rowers/braintreestuff.py +++ b/rowers/braintreestuff.py @@ -17,7 +17,7 @@ from rowers.tasks import ( # handle_send_email_transaction_notification, ) from rowers.utils import myqueue -import rowers.fakturoid as fakturoid +import rowers.idoklad as idoklad from braintree.exceptions.invalid_signature_error import InvalidSignatureError from braintree.exceptions.not_found_error import NotFoundError import time @@ -114,18 +114,18 @@ def send_invoice(subscription): else: r = rs[0] dologging('braintreewebhooks.log','Rower '+str(r)+'\n') - fakturoid_contact_id = fakturoid.get_contacts(r) - dologging('braintreewebhooks.log','Fakturoid Contact ID '+str(fakturoid_contact_id)+'\n') - if not fakturoid_contact_id: # pragma: no cover - fakturoid_contact_id = fakturoid.create_contact(r) - dologging('braintreewebhooks.log','Created Fakturoid Contact ID ' + - str(fakturoid_contact_id)+'\n') + idoklad_contact_id = idoklad.get_contacts(r) + dologging('braintreewebhooks.log','Idoklad Contact ID '+str(idoklad_contact_id)+'\n') + if not idoklad_contact_id: # pragma: no cover + idoklad_contact_id = idoklad.create_contact(r) + dologging('braintreewebhooks.log','Created Idoklad Contact ID ' + + str(idoklad_contact_id)+'\n') transactions = subscription.transactions if transactions: amount = transactions[0].amount dologging('braintreewebhooks.log','Transaction amount '+str(amount)+'\n') - id = fakturoid.create_invoice(r, amount, subscription_id, dosend=True, - contact_id=fakturoid_contact_id) + id = idoklad.create_invoice(r, amount, subscription_id, dosend=True, + contact_id=idoklad_contact_id) return id return 0 # pragma: no cover @@ -212,11 +212,13 @@ def make_payment(rower, data): l=rower.user.last_name, ) - fakturoid_contact_id = fakturoid.get_contacts(rower) - if not fakturoid_contact_id: - fakturoid_contact_id = fakturoid.create_contact(rower) - _ = fakturoid.create_invoice(rower, amount, transaction.id, dosend=True, contact_id=fakturoid_contact_id, - name=additional_text) + idoklad_contact_id = idoklad.get_contacts(rower) + if not idoklad_contact_id: + idoklad_contact_id = idoklad.create_contact(rower) + + _ = idoklad.create_invoice(rower, amount, transaction.id, dosend=True, + contact_id=idoklad_contact_id, + name=additional_text) _ = myqueue(queuehigh, handle_send_email_transaction, name, rower.user.email, amount) diff --git a/rowers/idoklad.py b/rowers/idoklad.py index 1da50022..2f74ac86 100644 --- a/rowers/idoklad.py +++ b/rowers/idoklad.py @@ -77,7 +77,6 @@ def get_contacts(rower): if res.status_code != 200: # pragma: no cover return None - data = res.json()['Data']['Items'] if len(data) >= 1: @@ -141,7 +140,7 @@ def create_invoice(rower, amount, braintreeid, dosend=True, contact_id=None, nam token = idoklad_token() if token is None: - return None + return 0 dologging('idoklad.log','Creating idoklad invoice for '+str(rower.user.email)+'\n') @@ -177,26 +176,29 @@ def create_invoice(rower, amount, braintreeid, dosend=True, contact_id=None, nam id = res.json()['Data']['Id'] if dosend: - url = invoice_url+'/'+str(id)+'/Send' - print(url) data = { - 'AttachmentIds': [id], - 'DocumentId': braintreeid, + 'AttachmentIds': [], + 'DocumentId': id, 'EmailBody': 'Dear customer, we are sending you the invoice for your subscription. Please do not hesitate to contact us if you have any questions. Best regards, Rowsandall Team', 'EmailSubject': 'Rowsandall Subscription Invoice', 'Method': 1, 'ReportLanguage': 3, - 'SendToSelf': True, + 'SendToSelf': True, + 'SendToPartner': True, + 'SendToAccountant': False, } - print(data) - print(email_url) + headers = { + 'Authorization': 'Bearer {access_token}'.format(access_token=token.access_token), + 'Content-Type': 'application/json', + 'Accept': 'application/json', + } res = requests.post(email_url, json=data, headers=headers) dologging('idoklad.log','Invoice Sent - status code '+str(res.status_code)+'\n') if res.status_code not in [200, 201]: - dologging('idoklad.log','Invoice Sent - reason '+str(res.reason)+'\n') + dologging('idoklad.log','Invoice Sent - reason '+str(res.text)+'\n') return id diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py index 0942905b..512b2429 100644 --- a/rowers/tests/mocks.py +++ b/rowers/tests/mocks.py @@ -57,6 +57,14 @@ from rowers.dataprep import delete_strokedata from redis import StrictRedis redis_connection = StrictRedis() +def mocked_idoklad_token(*args, **kwargs): # pragma: no cover + class MockToken: + def __init__(self, *args,**kwargs): + self.access_token = "aap" + + return MockToken() + + def mocked_grpc(*args, **kwargs): # pragma: no cover class insecure_channel: @@ -773,6 +781,9 @@ def mocked_requests(*args, **kwargs): with open('rowers/tests/testdata/rp3_list.json','r') as infile: rp3workoutlist = json.load(infile) + with open('rowers/tests/testdata/idoklad_default.json','r') as infile: + idokladdefault = json.load(infile) + rp3linkready = {'data': {'download': {'id': 591621, 'status': 'ready', 'link': 'https://rp3rowing-app.com/api/workouts/591621/download?type=csv'}}} with open('rowers/tests/testdata/example-session-strokes-with-impeller-data.json','r') as infile: @@ -1117,6 +1128,7 @@ def mocked_requests(*args, **kwargs): rp3tester = re.compile(r'.*?rp3rowing-app\.com') garmintester = re.compile(r'.*?garmin\.com') fakturoidtester = re.compile(r'.*?fakturoid\.cz') + idokladtester = re.compile(r'.*?idoklad\.cz') polarlistregex = r'.*?polaraccesslink\.com\/.*\/(\d+)$' polarlisttester = re.compile(polarlistregex) @@ -1487,6 +1499,43 @@ def mocked_requests(*args, **kwargs): else: # pragma: no cover return MockResponse(c2workoutdata,200) + + if idokladtester.match(args[0]): + if 'Invoices' in args[0]: + if 'Default' in args[0]: + response_data = idokladdefault + + return MockResponse(response_data,200) + + response = { + 'Data': { + 'Id': 1, + } + } + return MockResponse(response,200) + + if 'Contacts' in args[0]: + response = { + 'Data': { + 'Items': [ + { + 'Id': 1, + 'url':'aap', + } + ] + } + } + + return MockResponse(response,200) + + response = [ + { + 'Id':1, + 'url':'aap', + } + ] + return MockResponse(response, 200) + if fakturoidtester.match(args[0]): if 'invoices' in args[0]: response = { diff --git a/rowers/tests/test_braintree.py b/rowers/tests/test_braintree.py index ca540e2b..3d32d19c 100644 --- a/rowers/tests/test_braintree.py +++ b/rowers/tests/test_braintree.py @@ -74,11 +74,12 @@ class BraintreeUnits(TestCase): self.p2 = PaidPlan.objects.create(price=25,paymentprocessor='braintree') - @patch('rowers.fakturoid.requests.get',side_effect=mocked_requests) - @patch('rowers.fakturoid.requests.post',side_effect=mocked_requests) + @patch('rowers.idoklad.idoklad_token', side_effect=mocked_idoklad_token) + @patch('rowers.idoklad.requests.get',side_effect=mocked_requests) + @patch('rowers.idoklad.requests.post',side_effect=mocked_requests) @patch('rowers.braintreestuff.gateway', side_effect=MockBraintreeGateway) @patch('rowers.braintreestuff.myqueue') - def test_process_webhook(self,mock_get,mockpost,mocked_gateway,mocked_myqueue): + def test_process_webhook(self,mock_token, mock_get,mockpost,mocked_gateway,mocked_myqueue): n = notification() res = process_webhook(n) self.assertEqual(res,1) diff --git a/rowers/tests/test_payments.py b/rowers/tests/test_payments.py index 5f1cf614..0ecd7776 100644 --- a/rowers/tests/test_payments.py +++ b/rowers/tests/test_payments.py @@ -405,7 +405,7 @@ description: "" @patch('rowers.views.braintreestuff.gateway', side_effect=MockBraintreeGateway) - @patch('rowers.fakturoid.create_invoice',side_effect=mocked_invoiceid) + @patch('rowers.idoklad.create_invoice',side_effect=mocked_invoiceid) @patch('rowers.utils.myqueue') def test_purchase_trainingplan_view(self, mocked_gateway,mocked_invoiceid, mocked_myqueue): u = UserFactory() diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 0dcea5ecc29cb4ae8bce7f4ae92765a75e52c1cd..c7efdd5312a7dff0a614eb0c3858df24994204bc 100644 GIT binary patch literal 4000 zcmV;R4`1*fiwFpfnmlI$|8!+@bYx+4VJ>uIcmVC4NpBoC7J%>m6@m`QVG#CP__!#F zf^35^U}u8F$mBLCOC7mqq?XWK-v0fN-Ht5VDkM*uB3K3bV5qBW>-y@EZ|CvXZ!Rwm zUM)A<)z$i|Lo{%B@b$@~<7b<0wO*~yzgw>R<>vdY@1A$tuukyPnYSa?doWM-X~Y5UBCOa_qu@t{ZX&T zyxE@p`GJ4$`tQ1ntIcY;UA)3S-~acnKi%)Yytx$qwMz{Gy6>U;-*|ZP=-}Y^-2+HJ zBY%9q;qAdM*H@eVtHXcxFP59b{g>(M$7d%5=)M5?g5VkQk;Nl&COYB>e*-uII9{Zk z{@DLXcYW|n-);J5tIOqAhkthL&4tpT&#wCJA|Lk4^7LwbwmlK{$BR$4zCYmm)&327 zx=cTIo9;8;%SRjE@BIh96U1=5xcT&chi{Uob?3`}EYscp-1W&NTetJ=Rk*}WCZMD}LO?FV_bOb_^kFh9oq-?u1kR_EvG)|UN?tFx1* z-TGyBktlw!_4eM~>3=`C``wo7tJS){y*Yo8-hsdHF79^w@W_u|2{Cr~HQ62TKmxZZ zkpG0jp2Xb_{V2V=loaK_epHx@nZki$Jbn> zi+=p`?!LwRBHV>nOP#?aX&0-Yj%;um*z<#~h&#E8xF?7RE-1KD(who$5BKLzb;-Mx zinu#NjH*#S4G~Ayfe&(yRV45rQJC16x?kvRFFG9fIC*j zJwQd=C2>zerP1cSaTDQQm%InAh`TqzgVX5q&XqLdnC8RX*TY@F_<&X;?_P{dgnMP< zd_{Jgu!&%!hI^2b_WPXVJygWq83zO!y)H^oeSSXjj!=F+^q>}k${Fn6H`T5NA0u_;GV;O}tYIWHQI-=x= z=6SMZ$=ex`uP9=}!2p044S9i*(Ruq2zdbjrZisx6U+YknhD8!f`tW8&z9JuFx6_FQXg;_PvyP~zUvm!4Q zkq;(uS7l(@vK5sAP3FfSZ_y-;(~+v>Y0+M{GNUSLu@#YLYO04Y>ka?y8RgB5llp4jrZ08w%pt4%RI7?K%|M%I-Cx9 zZl0V$@-Amxt2!Y%!lJtUoXFQS+D8M3K@*>MOhv1xeT&bJK|bf+1`L|Mx6V@0+}k;k zugIP!Ysew1=6RvX_PM*9NZyjo4bw23^1!HxBGqUF^iqG3%EHY|xa(sGQ z>_o`d=EDp1kQdCgw5l~NycDgUpOehjq~Qr0FN7K&o_DUK-+or}d`0$rl3$LbsBIA}=qlv1l6k3!yfqd?CG!D_u0=g7 znRgYD_XdGLW7P!=lacvGewchTE)DjY(LPWpYR}JUv=8-=M>5u8)MQ-;j!ow8Nj_FY zUJL}~Xm5+IR5&Y7PDP_VdgDb@-BN-px;p8cytkg}Ay1HdW3k4Q6UwepDb&c1LY@th zt_NlaMOQ7G6Zx9vc@h%@qb370L@b(_K{J}?eMRJhktFk)N{a~8WPa+gIyquAmPwVF z5s@4DsYh%Qd21;BQ<0~l>)7P_)0UYr0(qbF@KpWqA{Sl9M(m8bpVmY^n&2?1WWI1V zmTi4+#~^RXIMG#C#lqQGb6S_Sq9|>WUty(g?_5!c)En#-b_r4?z!=p_hu#OKz9~x&hzPWYA;lcRh$c z7(qf(p--wIPsFHiQa^}3w=*SV9eQVr+IG_B`ccqZV+B<{Tm&yo>hFo3Dnjpbi!6^S z^ubL=>MKLft{(KsPP2i)s?bMYRLz^yfR7cS=QP(7sOEZvFd6i<4fr)ly)z6*s<|Gq zY`M*x&~ruTW7hDaPU_39TG-H!gFbgcb*#$F!Zc$w4SxpcB@g(jkS(H6(P;gg)Vzv} zI}V0C29<`7u6gtBYutr;(5JB*T<(vjLGO$9!F^ChCN$%25WO`3#5$=Db~5O(8Fz!| zeL}BmqLH(?ilXO+eiZc4M5}b^5V)eo9W`&>80eF-9#L0zgOnZrP3k9)UX1fv^i;N0 z+MJ{wDncKO2&o!iBPEN_H}unX>G<3k(>f8AaYso(kcqU)Pk!g)t`6 zIjPz8!|1)CAVD|adnj61k4?=R13e}IRu>PhR?R_Iycm6?#4i$Gb{yl_4O=e+o@1f^F~3>MgXHu>Rp)3 zfR8OfYY@FN7IkYGBKughaT+zdeiZc4P(-WK@I%?~4L5Jz80anK{#iP29>>_!yy*}4 zRt$);@X8`gCSG4#GIm8lTbndCq!?A`iP~I0ee?n*Did-qXYTUK18snf3S?axR!1p{Esc!@RAbLguH=fC=g0>FaWKuPnnm33(*=g3HE=$LuYXkn&bMq2pgPOnmcI5-6-gz@ut}#I8cEijPU@qdj9pJn%^O0`WW-us_$EMTcKr;{ zOD?*7dxAkhF?pTj=*ju zYe27ZtuD(&CXFr+ME!$i_h(51m%}6S5 zUbMbw^$oSYd844`-6G~H<1R{Ut6NUoo0rkMTzI8K?_yD@Z;evNK_7GBmCmk@0b294 ziF@-B`rS&_%E(=e*g9j+0KGM7rdKV1LIABt?tRhwvCzNU`p1Uj#gp#(=EILy{c?Nq z*+u{54;RbJ<+?xke7EWIgRVb-H~x26K4)Nfeg>bN_g@|__6I!LpXra^m_OfqTJ66- z{%(^vUTxm(`(u~hp3T+kZMQz_E-rRYD}7w8&(FHPOXuzOZ{8B=>IZp+i|Kk1U$S#bOFr@O7z zX|tF2`|UQ|Jlc=WfBY=n^vTc5i)FW6CJy=2yGM8HzK)-C>+{FopZxG+X0!Wqzx}85 z7XSG2^7%5|8Ne3+`~Qy@x4zgv`Q2kWd9*{lTBqmmT|&9se4n1i^K|KxNB;v$g~ literal 4001 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 H#DD<+r2IaO From f15a3d479a86175e88f4dd7fa9bf37374f947fc7 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 19 Nov 2024 16:31:51 +0100 Subject: [PATCH 13/32] tested --- rowers/tests/testdata/testdata.tcx.gz | Bin 4000 -> 3999 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index c7efdd5312a7dff0a614eb0c3858df24994204bc..476371d61f3e8e746883e08ee1e0ef82559d1515 100644 GIT binary patch literal 3999 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 F0RS=$K41U< literal 4000 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 From 099706dec5f0ac646a56515a2dabe3b73fb5cb51 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 7 Dec 2024 15:23:39 +0100 Subject: [PATCH 14/32] fixed --- rowers/dataroutines.py | 4 ++-- rowers/tests/testdata/testdata.tcx.gz | Bin 4000 -> 4001 bytes rowers/views/apiviews.py | 22 ++++++++++++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/rowers/dataroutines.py b/rowers/dataroutines.py index 9360b1b7..17579249 100644 --- a/rowers/dataroutines.py +++ b/rowers/dataroutines.py @@ -1289,10 +1289,10 @@ def parsenonpainsled(fileformat, f2, summary, startdatetime='', empowerfirmware= # handle FIT if (fileformat == 'fit'): # pragma: no cover try: - s = fitsummarydata(f2) + s = FitSummaryData(f2) s.setsummary() summary = s.summarytext - except: + except Exception as e: pass hasrecognized = True diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 3355de9792ee5cdb947aaf57fc7eb5dc11b989dd..e4b282767cbb0a0b00a3d19988f22f0eb76fbacd 100644 GIT binary patch literal 4001 zcmV;S4_@#eiwFq4Q&eXH|8!+@bYx+4VJ>uIcmVC4TW=dT7J%RLD-1uh4~tUg!o!Q} zx@eOwHbBxX+MwIF#ne_E?b@;-O)mZSOG>HZBp$TK-XS;x<{_{~bJKit$aClM*KaQ` z4qh)e+tt{c`i9>$_jO?eZY)yxx9w__FV>j~0tJ zZ{C>mZgaU>o71byMf!4k`f_>MZ5MYRzIaWC`%@fsZ~wwszB%nzuUGx=-@WaZ>wJT^ zPVjcS`rr(2*j#PS7X*NdU!FhvX?Kb*R_krwtxuQfsO{=#f8J+Tr(M7MwfDM#1N~92 z$-Ld3{rQ1^@A}8x#nooD+%8_@pYQ)$*Prh9U*22_|JtPn0p0h|{ck)xd311a{O$py zpOHVl-|+jvPuEwQ{;R`(_Ai&4!~K`(>!)WY1n9m1`GVjD@{z?Oawa|gF1vpF!*cU{wSLtv|J~pE5$QBPcNedgCuq|}_J6*=!s3og-1_=?_jYyp>hk|| z1LE$ufjcg7>+7fM-K*OFezJQjmWk}mmfH{VY?&VL31NPW`@e5d+^o*e)2%K0mse*e z&%5=j?jlkAVC(I@yVL)EaQC|{*H^1`e|vNOBE18D;a%MA_TiBqy%J*V@N2R=;DH2g zQy~8dg*}P85q$7~;g09K+u>&P+J17`7eD;+muG@I$MBEOn9ljHuJ4oB#N);OuaB>} zNEiM1=iPma`9-)3ua-K4NzyJ>K^@uPG_dCfT@iP36>(1x5nNDkr=&L(SISAon;M?#@=kJtld#;x*i3NqJ|O4R>D=cT2l*-YK}-V5lH>d;oW> zihF>HxJ%-mgi52$d*dd;y)JnVToHF~f(NJ3=bbBQ#xc!@yRV14fbjvXM&7*`nF#mF z#`%iuIAIgPMh*8MCGGb)$$O}XyE6_5GqWb)N*(XTU1S2bhe^*EY{r6s5Jn`1C5O?D+`BHw|y<^Sq!*BCoRN8K7vy zW=5lZO)@Xmq-P7HA&)p2-M&R>hsitR1%oC^%Y;Sk`8koV$ezy@8e7#o&x|Hcggmx+ z{%-P|b8i`tG@hLFqLj?Kwyyc@MqmXw7BZ^Aqqb=&aZ8AR&`CaaG#tO4)o_9rSX=g=V zDk2|D;;zcTv}G$Q1)9u{LEfTC8mA*w%hRI0Ze>PQ)M6_l&&E4ll-9;rGACzFg`w&8)0cU%CM4ZnCG)my z)^%*Pw4;#sMpzfI5h+W)`S3;{Zxd{T-m0>$#WnKxC2uPtPbPR>b(MIWOnkn{{4jYj zmQYn)C82CxUF(544*6gRQPnv?V%ZuS-*o#i$Rn7D#2W9d18ljs)0cTj{Ubc989`#F)XX|#_95Q8Q@@0f~KQTrC3AA@|(y$u*NeQ%wmqPe$o zB43d`Pu7q_R?YK5lgYj1RzE*T-W#+?s?pw2QG0$yy+8K}+10bp{=Pq)K(oTQ0XKzGwoe(`V^7kcQk#29nuosml$D=K& z;XNo1uW5M0LD+fYiU($T6ig1KR+j#uSvrbHeLudK0NPSNx%K9=J|^3`6Ry_NmXOx zy=xVf_at9YlvbhvCQyy`!A(ZDZ{FJh@^S=dywZo~W6@Q}XC?De5qWDYh)U)I6kUsY zRx7r4B=Xi!`lljKMc1*(^`|W}V+8U(=i#aP;YBXGj*ZwEbw90%d^EvfRLOkd zY%JUQ-i|@ul5wJ|u8M`TvF5ZcZADSqB)`H+-QKyPR^6P)SLDgD!B8a7`I}{LSK<9 zM`BL6hoC}F(9qwr|7kVjy~~|%UDS>D2#iHj?jM34Dnl<7p_kk+1#|=N4HW zRp^78jMP_#o?SiYlbvP*fmNZ8zNnfvrvV=;LeFWgCs57x2w^hlYa8%ul6q$tkW_O$ zV%c(=Iicr@(8sLdN1fD{UA3^G9|wKzgz8w8nT2V_Y8w6w&`TchRUunMp`y|HIjMOS z8Fw5Ec?>EIA6@h2-PgDa^`K89js z(ffp6*F+;{a}`C;4gDzSqls4O(jjm~jXP@IyfM%xWj&&<>;@@2{+rZK9=#anwdkpA ztF$>uJye7~7!gu6z(z_Ip>OD??b7kNGp2PSD&vllf*=!VpMz~#`a$&8u-CQE$qQpl zrgKuW>xa>MLqURW!1qwJupXP5HwJo40<0{!Lkc*Vj=0#;G6&JKL8t4Qg%pb}Tso@( zpDIG{3|P`-!HH)!dDNK4(}8>gwxR%C=LXrsj=;o{a!Toz%N9 znE@YLg4Q5{M z@U0jSW#N@Ym`uFBwq)#zg0?nkY)CPx&=a+}e){MIOjIshjFzcr z%ad8&tT}Rr(eGL&dX<`I#Wt7D^c}gomWk+fbG?(vBxtp?%mMUa*D?`wOWvUM(u}*Q z+w~#0Otd1Xa^%|3s&DR#K2(H0~Xc@UvFT4u5Wg@0+I`jc2(@>?Uc?0NUZkY&(QD@gjYH67>K+h(C(wpa@ z>~hA?dg+XU-evSrW!HP;qBVEWjJr|LN8?eMhwrIu2?n&F?HK5hazhoR)N|Pq3}`{y zQP4|ns6slaw^B562Tjcz1${6q7<5uEu4t-8Q}aeaPsz9=WorfRTyx}3-K7(A%S6zw zY3se8%v?_`Xgi2L7g;l?!Z$wnX4lUEeKeA+JDt==KN-88nwmF+p2>){y6{ba(Cqpd zpqE^D1v>Ot6n$PQs15idpbrKZb^Y)|PTrpgdTQRhA@q4AYrvpG&v7#7+xqpx=-C7z zUF0skC?z%g+=-&09|65Ho^4dQbb`Z@E}dDSmx|EGyrwPaq~2rE0pGV0j4{v)8D}x5 zvUEZyT50LPa$iY|6GD-FMvEFFQ} zO4fj0<;aaFlX2-l>zg--ez%gfZk@YGWrMcR=K4|4`&@maM9+RQt6R3Yeh__L$(oT= z-n?ji(drv&ee*^^&$~s;RmNSE*jBfkxHm7Oce(INiQdJcQr{Y-j)Okt!YiF!9|N@J zX%qM6CG@+Mtd)_w7_oK6o&kDm(oC;f0EGZrkKFsB_hX@dxAl(=$BSp(_05OxulnWo zx64T1zRzrSf9|*c zkly0&UtRvXOm_zG1;GCQuIcmVC4TW=Ic7J%RR6&4T4!zwlBQl~DC zaYP`iMFKVoD4VxcV&?BpuloLcf3bM` z_N_VYE>2f#b98pPNMCM_UM)|%&EopQ7jNk9?iBmoyKgwl{iA;MX4Sv{fJ=Ir8lK>)b;iX@kz0nQq>5qCt z=H2GyUmy7Qu7A*-oL#Jzo5dUa>;3=i`lH?c%gamQw_R!w&`l5B{l>e8clP!UK0JW* zGxEnz8{Y3dJ3qVV@7?`p|7v-0clTxb`q9fn0(3us{6O#=dEeqbITIamguemo0~{>U zP9OJw+@0?|>${8o`Ra6e@9tk6dwHRB=<~C_JIRMVTOOUQUv3VC{lVg^t)C8fxZ1rz zPnPM&Zqj|`d--DHr@cSoJ46fzi_1@+cDSEJtvg=+W0~&$x2|9Qe15upHT(DH>6ct? zezg91+4Y-Wmlsb~>(~AA-~E*zkxuh_ck+69h&Ekh_vfc8EUvl4m9L+4?^dU;PybIh zAnuwQxaJa9zJ9dczN-EE!|hwKOk^*&Tz!x)m+1i?66VLa`}+#Ti`DUQy0vBh>g?s= zlWzUGJ4qBj+j@2H?&!at-TijU`PpjSU)`L)NbkTmyo=l2K0oq{S3-;(eoeLq+>*dm z3go|{up@Cjg3lf>T=RUlJ6w)lo3AeW{MSFec_z4a4FB?s>74)S`aX$GJXq}h`tq8K zbkQ$=-u1VbUxe%MYN<1rB<*4q)R7HN1ABhZ6>%q55%&ZU!370(N_ta4?&0R#sV;f9 zQW1A&h*34lry+t1a*wm&?rcTeW0H3(Uc)_>ly`>NaQ78)x3nGSor1d!h6-}WTX4s! zxCf|+yCm*Os5IKVH*O-_>yr1t6>;|_cyJnh-no)y9MgQb`+B$w7$4AT?9gyotqY+EP1{Kd8&&% zRWrrYJ|t64bfz4ll=R)OosZ13R7BpIn3Q^z%#)ZBb!3eIqDsSyv7|jeC-OE_ zL_X>1OsGn}f><(2XK6;GJyt|MntwZS#CZQCb^}Pp_iNo{wOB)9|J~&kLF)@+y0t0g6U! zW;EK@B=cfTdbU6s@`#hs?OT*~n7lJyFleH*Ojy*OpA-3t?D=e=u~p6U%xL07$YY!5 zuP4tr_m%-kzdzw6!Kz#A*f_tsA$BdkspV=Hz7$pYREfoGJiwzTn~8! zBLRY{Nrva5GVhyiKMHv^Y*AG6eBh!Qo^LWg3VCNRqNrp(+M?duCiCNv-{#(`TAZ3-tx8#b-d}vnPDCE7Nh)(0Zwd{)K z+lMyVk3pVc+Y(Eo+gt03>h__<=SLw=#xX=y6FezPeohsYt|IbctT3zQc~`WSc2?x2 zBJ#l`?y3w-TehN7pvn9gE)pb8_ZHzMdKz z&bhbFBWgx_L70rpH+z1Vd^8jw1{L|(bo=Q?Y=m;R6jhW~7@BTBeVG?)LelM3GH=Uf zUB^~SI|_Mkgmn=ck+S5Q4{rqWHo-RNtt#tUTqA!|^0p%KWP;aKSBb~T#OIsL50e*T z302iq63W)qwH}z`kPn6sRh<(gmaVbzO}8I|Jc5ZxtnuDDz?OSEeVIo#5{NWWT8Gmi z&&`uFNZ#eFYgH#iM_5$1pA-3-M*C<0F=*oRj;UxBwQuqHG05lK+kipS_tse|ntMAZ z@)gGl>3dr^6EJlc{P z-mUWRnua$_o^$t8mG{;sOE9(!%*m4%&^;Z!Fe$azfcPDuo*PQOL7F z()GX$q3Eh*b0S~UJWpbRVANz_hKNNoGiXNhyswCSFp^|mQ)v-_n#@lzJ2t*=xFcS zTGV5Z-{s!w=J^ncT6J?GUy&zAl7+?uD)KQD&B<|Xo*#w0Gri5Z8t}0q^ql5;0@YlP5GI4ZwgJB;sdt6}Nj29a zmMyoL6MC))easqu)Jc8WRSO&XanR>ZsE$>cS(s+5rs2;3z2pI36|zMXDjKbylbTnN zamT@s$Dq>i(KT=0O^v%y5BfBAgUkK#H0XWNKDf8a$b@Fx4WhROfLJH>!A=G}Hsfv( zy-(gS5frb(2s&XnrM|S9RgR>xTEIH8v}h()+6f5ZjiF$ze)Y%(Tj0ji=N81 zN}H3^Lq+I=5g}CrY@}on`i6emE*+mcV_GMoGVUlT2r`lOIoOt^A4G2rdtLjSyfDUO zIwv)|ei*$s6eQ>dd=Etn>#?bMW1z<*z{-LI;Pa}Yfnbh@rtNU`X`rL!9F zsUq~wfF)f-w7Gs1^n@l7fhs|ZX*z3~H6Q*kdTRnJ zt8bXyWSXY6ES+KW-gqml((u`qUFU{c&D|L2bB3j$uD+h7Y&#WdYThX5*$80NNxch` z8St?sXbqxw#-eU5Lu4O|Hcq2v*N=ie8j5Ij8h$7nzTxK08w0(i+&@d_&EpuGnm7Fc z---cI7G7C|$;9hxOUAA!Xls+kh7_X;JyDzMr;lF1MCHQ8Xqk#e?wSvO9Q16WL(-wQ zJelRqnj?1@{kCPISE+ecY;);M-;uj*nTTFD*E^X^f>uk*96%qoEfYbvIKR!SI;w2^PnR1 zcH3G(rRGWDHcE4+oZMUA`GRbw3VAxpj24fviXBlT^-A4Jb+g0L=LFTobo@LSM! z9Q4*WL{xRvkZ7AXZ~Bg0_Qo?=RnXRfn@p-kQ}YJVCp*nL)Me>7bZx+&dTw4q&qgRa zX*B3*IwcsbjnXiBXDsAIOAUGsZNQ(tBiF`+o=8=AKYLZ4T%1`Im%94CXmtzSQko=p(a zMefpzQc}auohTam5zss1*+!L1CpawW(wP-{sR(_{YubWN>OB@6@O>-67z4eKaTbFr zODBY)mA1D+-)ioL(Mztr395|T5Q|pY-fF;ay>y1rhrFh(E^-&4=wfHH((r4^(h=CM zWDV$5j@*bc8J7;UzIlV_w<}re*13yRHfRfNt{(-x&($|d^z0|Ix@DW|2hr!1tQkq= z&5PC-t-hhwH*Xa5yj{dxW!y!HZFS3ud-F1SmkY0y=v^!-^{r9rIOt<8ywchAF+gjc zHgRuWLcd+fS{b>E5nE^M8KAc&&Gf1TPza#)$h|3gKNk8ATR(0%SUm2|FF!mz>zA9u z?@sz3e>qv6F4z6u_uEb1?{)niyz_r9;}NiBegWSd_dgyib_d+qo$2Fm%%3kmt#;oZ zJh(_4&n`af`?O1M&&Ao>O}Bp8ot$i+R{FSFAHVGSE}ggAyRK|D;Q1XTjCaU+=bB zr_EkI?YG@<`Dnj5|H1Qg(}%w;PnO+gnKx4B!WV-Tw!RD_`uM{Pr;&-r1sFtJ{eWJ? GfB^svO&0 Date: Sat, 7 Dec 2024 15:47:25 +0100 Subject: [PATCH 15/32] fix --- rowers/dataroutines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rowers/dataroutines.py b/rowers/dataroutines.py index 17579249..d5f1e168 100644 --- a/rowers/dataroutines.py +++ b/rowers/dataroutines.py @@ -1604,7 +1604,7 @@ def read_data(columns, ids=[], doclean=True, workstrokesonly=True, debug=False, datadf = pl.concat(data) existing_columns = [col for col in columns if col in datadf.columns] datadf = datadf.select(existing_columns) - except (ShapeError, SchemaError): + except (ShapeError, SchemaError, ColumnNotFoundError): data = [ df.select(columns) for df in data] From 931bab29eab09c9f7a9cd7714b939cdc680859f8 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 7 Dec 2024 16:38:58 +0100 Subject: [PATCH 16/32] creating auth url, not implemented callback yet --- rowers/integrations/__init__.py | 2 + rowers/integrations/intervals.py | 92 ++++++++++++++++++++++++++++++++ rowers/models.py | 5 ++ rowsandall_app/settings.py | 15 ++++++ 4 files changed, 114 insertions(+) create mode 100644 rowers/integrations/intervals.py diff --git a/rowers/integrations/__init__.py b/rowers/integrations/__init__.py index dc76fdb1..409a1ce5 100644 --- a/rowers/integrations/__init__.py +++ b/rowers/integrations/__init__.py @@ -5,6 +5,7 @@ from .sporttracks import SportTracksIntegration from .rp3 import RP3Integration from .trainingpeaks import TPIntegration from .polar import PolarIntegration +from .intervals import IntervalsIntegration importsources = { 'c2': C2Integration, @@ -15,5 +16,6 @@ importsources = { 'tp':TPIntegration, 'rp3':RP3Integration, 'polar': PolarIntegration, + 'intervals': IntervalsIntegration, } diff --git a/rowers/integrations/intervals.py b/rowers/integrations/intervals.py new file mode 100644 index 00000000..e6d7e3cd --- /dev/null +++ b/rowers/integrations/intervals.py @@ -0,0 +1,92 @@ +from .integrations import SyncIntegration, NoTokenError, create_or_update_syncrecord, get_known_ids +from rowers.models import Rower, User, Workout, TombStone +from rowingdata import rowingdata + +from rowers import mytypes + +from rowers.rower_rules import is_workout_user, ispromember +from rowers.utils import myqueue, dologging, custom_exception_handler + +import urllib +import gzip +import requests +import arrow +import datetime +import os +from uuid import uuid4 +from django.utils import timezone +from datetime import timedelta + +from rowsandall_app.settings import ( + INTERVALS_CLIENT_ID, INTERVALS_REDIRECT_URI, INTERVALS_CLIENT_SECRET, SITE_URL +) + +import django_rq +queue = django_rq.get_queue('default', default_timeout=3600) +queuelow = django_rq.get_queue('low', default_timeout=3600) +queuehigh = django_rq.get_queue('high', default_timeout=3600) + +headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json' +} + +intervals_authorize_url = 'https://intervals.icu/oauth/authorize?' +intervals_token_url = 'https://intervals.icu/oauth/token' + +class IntervalsIntegration(SyncIntegration): + def __init__(self, *args, **kwargs): + super(IntervalsIntegration, self).__init__(*args, **kwargs) + self.oauth_data = { + 'client_id': INTERVALS_CLIENT_ID, + 'client_secret': INTERVALS_CLIENT_SECRET, + 'redirect_uri': INTERVALS_REDIRECT_URI, + 'authorization_uri': intervals_authorize_url, + 'content_type': 'application/json', + 'tokenname': 'intervals_token', + 'expirydatename': 'intervals_exp', + 'refreshtokenname': 'intervals_r', + 'bearer_auth': True, + 'base_uri': 'https://intervals.icu/api/v1/', + 'grant_type': 'refresh_token', + 'headers': headers, + 'scope': 'ACTIVITY:WRITE' + } + + def get_token(self, code, *args, **kwargs): + return super(IntervalsIntegration, self).get_token(code, *args, **kwargs) + + def get_name(self): + return 'Intervals' + + def get_shortname(self): + return 'intervals' + + def open(self, *args, **kwargs): + dologging('intervals.icu.log', "Getting token for user {id}".format(id=self.rower.id)) + token = super(IntervalsIntegration).open(*args, **kwargs) + return token + + def createworkoutdata(self, w, *args, **kwargs) -> str: + return NotImplemented + + def workout_export(self, workout, *args, **kwargs) -> str: + return NotImplemented + + def get_workouts(workout, *args, **kwargs) -> int: + return NotImplemented + + def get_workout(self, id, *args, **kwargs) -> int: + return NotImplemented + + def get_workout_list(self, *args, **kwargs) -> list: + return NotImplemented + + def make_authorization_url(self, *args, **kwargs): + return super(IntervalsIntegration, self).make_authorization_url(*args, **kwargs) + + def token_refresh(self, *args, **kwargs): + return super(IntervalsIntegration, self).token_refresh(*args, **kwargs) + + + diff --git a/rowers/models.py b/rowers/models.py index 857a2680..635bf3ca 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -1240,6 +1240,11 @@ class Rower(models.Model): strava_auto_import = models.BooleanField(default=False) strava_auto_delete = models.BooleanField(default=False) + intervals_token = models.CharField( + default='', max_length=200, blank=True, null=True) + intervals_exp = models.DateTimeField(blank=True, null=True) + intervals_r = models.CharField(default='', max_length=200, blank=True, null=True) + privacychoices = ( ('visible', 'Visible'), ('hidden', 'Hidden'), diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py index 28f52fca..601a1652 100644 --- a/rowsandall_app/settings.py +++ b/rowsandall_app/settings.py @@ -296,6 +296,21 @@ C2_CLIENT_SECRET = CFG['c2_client_secret'] C2_REDIRECT_URI = CFG['c2_callback'] # C2_REDIRECT_URI = "http://localhost:8000/call_back" +# Intervals.icu +try: + INTERVALS_CLIENT_ID = CFG['intervals_client_id'] +except KeyError: + INTERVALS_CLIENT_ID = '0' + +try: + INTERVALS_CLIENT_SECRET = CFG['intervals_client_secret'] +except KeyError: + INTERVALS_CLIENT_SECRET = 'aa' +try: + INTERVALS_REDIRECT_URI = CFG['intervals_callback'] +except KeyError: + INTERVALS_REDIRECT_URI = 'http://localhost:8000/intervals_icu_callback' + # Strava STRAVA_CLIENT_ID = CFG['strava_client_id'] From 3dc41777ceea1dceef723a6bbd01f9f9fd145323 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 8 Dec 2024 12:38:28 +0100 Subject: [PATCH 17/32] fix --- rowsandall_app/settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py index 28f52fca..5e1aae1f 100644 --- a/rowsandall_app/settings.py +++ b/rowsandall_app/settings.py @@ -463,7 +463,8 @@ OAUTH2_PROVIDER = { "https", "rowingcoachexport", "com.performancephones.crewnerd", - "pocketcox"], + "pocketcox", + "app"], 'ACCESS_TOKEN_MODEL': 'oauth2_provider.AccessToken', 'APPLICATION_MODEL': 'oauth2_provider.Application', 'REFRESH_TOKEN_MODEL': 'oauth2_provider.RefreshToken', From 53e6fefbfe4b1bd4541c97209410993c9908aaf4 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 8 Dec 2024 17:44:45 +0100 Subject: [PATCH 18/32] import somewhat working (workout type not) --- rowers/integrations/integrations.py | 2 +- rowers/integrations/intervals.py | 102 +++++++++++++++++++-- rowers/models.py | 7 +- rowers/tasks.py | 69 ++++++++++++++ rowers/templates/menu_workouts.html | 1 + rowers/templates/rower_exportsettings.html | 2 + rowers/views/importviews.py | 32 +++++++ rowsandall_app/urls.py | 1 + static/img/intervals_icu.png | Bin 0 -> 3776 bytes static/img/ms-icon-120x120.png | Bin 0 -> 13739 bytes 10 files changed, 202 insertions(+), 14 deletions(-) create mode 100644 static/img/intervals_icu.png create mode 100644 static/img/ms-icon-120x120.png diff --git a/rowers/integrations/integrations.py b/rowers/integrations/integrations.py index 0cfaf0ad..2ff231a2 100644 --- a/rowers/integrations/integrations.py +++ b/rowers/integrations/integrations.py @@ -109,7 +109,7 @@ class SyncIntegration(metaclass=ABCMeta): if 'grant_type' in self.oauth_data: if self.oauth_data['grant_type']: post_data['grant_type'] = self.oauth_data['grant_type'] - if 'strava' in self.oauth_data['autorization_uri']: + if 'strava' in self.oauth_data['authorization_uri']: post_data['grant_type'] = "authorization_code" if 'json' in self.oauth_data['content_type']: diff --git a/rowers/integrations/intervals.py b/rowers/integrations/intervals.py index e6d7e3cd..185ef8d9 100644 --- a/rowers/integrations/intervals.py +++ b/rowers/integrations/intervals.py @@ -6,6 +6,7 @@ from rowers import mytypes from rowers.rower_rules import is_workout_user, ispromember from rowers.utils import myqueue, dologging, custom_exception_handler +from rowers.tasks import handle_intervals_getworkout import urllib import gzip @@ -26,13 +27,25 @@ queue = django_rq.get_queue('default', default_timeout=3600) queuelow = django_rq.get_queue('low', default_timeout=3600) queuehigh = django_rq.get_queue('high', default_timeout=3600) + +def seconds_to_duration(seconds): + hours = seconds // 3600 + minutes = (seconds % 3600) // 60 + remaining_seconds = seconds % 60 + + # Format as "H:MM:SS" or "MM:SS" if no hours + if hours > 0: + return f"{int(hours)}:{int(minutes):02}:{int(remaining_seconds):02}" + else: + return f"{int(minutes)}:{int(remaining_seconds):02}" + headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } intervals_authorize_url = 'https://intervals.icu/oauth/authorize?' -intervals_token_url = 'https://intervals.icu/oauth/token' +intervals_token_url = 'https://intervals.icu/api/oauth/token' class IntervalsIntegration(SyncIntegration): def __init__(self, *args, **kwargs): @@ -47,14 +60,33 @@ class IntervalsIntegration(SyncIntegration): 'expirydatename': 'intervals_exp', 'refreshtokenname': 'intervals_r', 'bearer_auth': True, - 'base_uri': 'https://intervals.icu/api/v1/', + 'base_url': 'https://intervals.icu/api/v1/', 'grant_type': 'refresh_token', 'headers': headers, - 'scope': 'ACTIVITY:WRITE' + 'scope': 'ACTIVITY:WRITE, LIBRARY:READ', } def get_token(self, code, *args, **kwargs): - return super(IntervalsIntegration, self).get_token(code, *args, **kwargs) + post_data = { + 'client_id': str(self.oauth_data['client_id']), + 'client_secret': self.oauth_data['client_secret'], + 'code': code, + } + + response = requests.post( + intervals_token_url, + data=post_data, + ) + + if response.status_code not in [200, 201]: + dologging('intervals.icu.log',response.text) + return [0,"Failed to get token. ",0] + + token_json = response.json() + access_token = token_json['access_token'] + athlete = token_json['athlete'] + + return [access_token, athlete, ''] def get_name(self): return 'Intervals' @@ -63,8 +95,8 @@ class IntervalsIntegration(SyncIntegration): return 'intervals' def open(self, *args, **kwargs): - dologging('intervals.icu.log', "Getting token for user {id}".format(id=self.rower.id)) - token = super(IntervalsIntegration).open(*args, **kwargs) + # dologging('intervals.icu.log', "Getting token for user {id}".format(id=self.rower.id)) + token = super(IntervalsIntegration, self).open(*args, **kwargs) return token def createworkoutdata(self, w, *args, **kwargs) -> str: @@ -73,13 +105,63 @@ class IntervalsIntegration(SyncIntegration): def workout_export(self, workout, *args, **kwargs) -> str: return NotImplemented - def get_workouts(workout, *args, **kwargs) -> int: - return NotImplemented + def get_workout_list(self, *args, **kwargs) -> int: + url = self.oauth_data['base_url'] + 'athlete/0/activities?' + startdate = timezone.now() - timedelta(days=365) + enddate = timezone.now() + timedelta(days=1) + url += 'oldest=' + startdate.strftime('%Y-%m-%d') + '&newest=' + enddate.strftime('%Y-%m-%d') + headers = { + 'accept': '*/*', + 'authorization': 'Bearer ' + self.open(), + } + + response = requests.get(url, headers=headers) + if response.status_code != 200: + dologging('intervals.icu.log', response.text) + return [] + + data = response.json() + known_interval_ids = get_known_ids(self.rower, 'intervalsid') + + workouts = [] + + for item in data: + i = item['id'] + r = item['type'] + d = item['distance'] + ttot = seconds_to_duration(item['moving_time']) + s = item['start_date'] + s2 = '' + c = item['name'] + if i in known_interval_ids: + nnn = '' + else: + nnn = 'NEW' + + keys = ['id','distance','duration','starttime', + 'rowtype','source','name','new'] + + values = [i, d, ttot, s, r, s2, c, nnn] + + ress = dict(zip(keys, values)) + workouts.append(ress) + + return workouts + def get_workout(self, id, *args, **kwargs) -> int: - return NotImplemented + _ = self.open() + r = self.rower - def get_workout_list(self, *args, **kwargs) -> list: + record = create_or_update_syncrecord(r, None, intervalsid=id) + + _ = myqueue(queuehigh, + handle_intervals_getworkout, + self.rower, + self.rower.intervals_token, + id) + + def get_workouts(workout, *args, **kwargs) -> list: return NotImplemented def make_authorization_url(self, *args, **kwargs): diff --git a/rowers/models.py b/rowers/models.py index 635bf3ca..2075d2cf 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -1242,8 +1242,7 @@ class Rower(models.Model): intervals_token = models.CharField( default='', max_length=200, blank=True, null=True) - intervals_exp = models.DateTimeField(blank=True, null=True) - intervals_r = models.CharField(default='', max_length=200, blank=True, null=True) + intervals_owner_id = models.CharField(default='', max_length=200,blank=True, null=True) privacychoices = ( ('visible', 'Visible'), @@ -3696,6 +3695,7 @@ class Workout(models.Model): uploadedtogarmin = models.BigIntegerField(default=0) uploadedtorp3 = models.BigIntegerField(default=0) uploadedtonk = models.BigIntegerField(default=0) + uploadedtointervals = models.BigIntegerField(default=0) forceunit = models.CharField(default='lbs', choices=( ('lbs', 'lbs'), @@ -3851,6 +3851,7 @@ class SyncRecord(models.Model): c2id = models.BigIntegerField(unique=True,null=True,default=None) tpid = models.BigIntegerField(unique=True,null=True,default=None) rp3id = models.BigIntegerField(unique=True,null=True,default=None) + intervalsid = models.BigIntegerField(unique=True, null=True, default=None) def save(self, *args, **kwargs): if self.workout: @@ -3866,7 +3867,7 @@ class SyncRecord(models.Model): str2 = '' - for field in ['stravaid', 'sporttracksid', 'nkid', 'c2id', 'tpid']: + for field in ['stravaid', 'sporttracksid', 'nkid', 'c2id', 'tpid', 'intervalsid']: value = getattr(self, field, None) if value is not None: str2 += '{w}: {v},'.format( diff --git a/rowers/tasks.py b/rowers/tasks.py index bad2cc3c..6fc8793a 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -24,6 +24,7 @@ from rowers.courseutils import ( InvalidTrajectoryError ) from rowers.emails import send_template_email +from rowers.mytypes import fitmappinginv from rowers.nkimportutils import ( get_nk_summary, get_nk_allstats, get_nk_intervalstats, getdict, strokeDataToDf, add_workout_from_data @@ -59,6 +60,8 @@ import rowingdata from rowingdata import make_cumvalues, make_cumvalues_array from uuid import uuid4 from rowingdata import rowingdata as rdata +from rowingdata import FITParser as FP +from rowingdata.otherparsers import FitSummaryData from datetime import timedelta @@ -3485,6 +3488,72 @@ def handle_nk_async_workout(alldata, userid, nktoken, nkid, delaysec, defaulttim return workoutid +@app.task +def handle_intervals_getworkout(rower, intervalstoken, workoutid, debug=False, **kwargs): + authorizationstring = str('Bearer '+intervalstoken) + headers = { + 'authorization': authorizationstring, + } + + url = "https://intervals.icu/api/v1/activity/{}".format(workoutid) + + response = requests.get(url, headers=headers) + if response.status_code != 200: + return 0 + + data = response.json() + try: + title = data['name'] + except KeyError: + title = 'Intervals workout' + + try: + workouttype = fitmappinginv[data['type']] + print(data['type']) + except KeyError: + workouttype = 'water' + + url = "https://intervals.icu/api/v1/activity/{workoutid}/fit-file".format(workoutid=workoutid) + + response = requests.get(url, headers=headers) + + if response.status_code != 200: + return 0 + + try: + fit_data = response.content + fit_filename = 'media/'+f'{uuid4().hex[:16]}.fit' + with open(fit_filename, 'wb') as fit_file: + fit_file.write(fit_data) + except Exception as e: + return 0 + + try: + row = FP(fit_filename) + rowdata = rowingdata.rowingdata(df=row.df) + rowsummary = FitSummaryData(fit_filename) + duration = totaltime_sec_to_string(rowdata.duration) + distance = rowdata.df[" Horizontal (meters)"].iloc[-1] + except Exception as e: + print(e) + return 0 + + uploadoptions = { + 'secret': UPLOAD_SERVICE_SECRET, + 'user': rower.user.id, + 'boattype': '1x', + 'workouttype': workouttype, + 'file': fit_filename, + 'title': title, + 'rpe': 0, + 'notes': '', + 'offline': False, + } + + url = UPLOAD_SERVICE_URL + handle_request_post(url, uploadoptions) + + return 1 @app.task def handle_c2_getworkout(userid, c2token, c2id, defaulttimezone, debug=False, **kwargs): diff --git a/rowers/templates/menu_workouts.html b/rowers/templates/menu_workouts.html index b85f728f..2beafb52 100644 --- a/rowers/templates/menu_workouts.html +++ b/rowers/templates/menu_workouts.html @@ -57,6 +57,7 @@
  • SportTracks
  • Polar
  • RP3
  • +
  • Intervals.icu
  • diff --git a/rowers/templates/rower_exportsettings.html b/rowers/templates/rower_exportsettings.html index 4990ce37..866a771a 100644 --- a/rowers/templates/rower_exportsettings.html +++ b/rowers/templates/rower_exportsettings.html @@ -123,6 +123,8 @@ alt="connect with RP3" width="130">

    connect with Rojabo

    +

    connect with intervals.icu

    {% endblock %} diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index f5270e17..486155b1 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -24,6 +24,7 @@ importauthorizeviews = { 'nk': 'rower_integration_authorize', 'rp3': 'rower_integration_authorize', 'garmin': 'rower_garmin_authorize', + 'intervals': 'rower_integration_authorize', } @@ -173,6 +174,37 @@ def rower_process_twittercallback(request): # pragma: no cover # Process Polar Callback +@login_required() +def rower_process_intervalscallback(request): + integration = importsources['intervals'](request.user) + r = getrower(request.user) + try: + code = request.GET['code'] + res = integration.get_token(code) + except MultiValueDictKeyError: + message = "The resource owner or authorization server denied the request" + messages.error(request, message) + + url = reverse('rower_exportsettings_view') + return HttpResponseRedirect(url) + + access_token = res[0] + athlete = res[1] + if access_token == 0: + message = res[1] + message += 'Connection to intervals.icu failed.' + messages.error(request, message) + url = reverse('rower_exportsettings_view') + return HttpResponseRedirect(url) + + r.intervals_token = access_token + r.intervals_owner_id = athlete['id'] + r.save() + + successmessage = "Tokens stored. Good to go. Please check your import/export settings" + messages.info(request, successmessage) + url = reverse('rower_exportsettings_view') + return HttpResponseRedirect(url) @login_required() def rower_process_polarcallback(request): diff --git a/rowsandall_app/urls.py b/rowsandall_app/urls.py index caf20824..67c26a3d 100644 --- a/rowsandall_app/urls.py +++ b/rowsandall_app/urls.py @@ -94,6 +94,7 @@ urlpatterns += [ re_path(r'^rp3\_callback', rowersviews.rower_process_rp3callback), re_path(r'^twitter\_callback', rowersviews.rower_process_twittercallback), re_path(r'^idoklad\_callback', rowersviews.process_idokladcallback), + re_path(r'^intervals\_icu\_callback', rowersviews.rower_process_intervalscallback), re_path(r'^i18n/', include('django.conf.urls.i18n')), re_path(r'^tz_detect/', include('tz_detect.urls')), re_path(r'^logo/', logoview), diff --git a/static/img/intervals_icu.png b/static/img/intervals_icu.png new file mode 100644 index 0000000000000000000000000000000000000000..a333c8b83e7bcfe8daba0691f4ec10014688b358 GIT binary patch literal 3776 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 Date: Mon, 9 Dec 2024 20:20:32 +0100 Subject: [PATCH 19/32] more changes --- rowers/dataroutines.py | 1 + rowers/models.py | 8 +++++-- rowers/mytypes.py | 38 ++++++++++++++++++++++++++++++++++ rowers/tasks.py | 8 +++---- rowers/uploads.py | 47 +++++++++++++++++++++++++++++++++++------- 5 files changed, 88 insertions(+), 14 deletions(-) diff --git a/rowers/dataroutines.py b/rowers/dataroutines.py index d5f1e168..61282da7 100644 --- a/rowers/dataroutines.py +++ b/rowers/dataroutines.py @@ -1367,6 +1367,7 @@ def get_workouttype_from_fit(filename, workouttype='water'): return 'water' try: workouttype = mytypes.fitmappinginv[fittype] + return workouttype except KeyError: # pragma: no cover return workouttype diff --git a/rowers/models.py b/rowers/models.py index 2075d2cf..610cd019 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -372,7 +372,7 @@ def update_records(url=c2url, verbose=True): # Create a DataFrame df = pd.DataFrame(rows, columns=headers) - except: # pragma: no cover + except: # pragma: no cover df = pd.DataFrame() if not df.empty: @@ -1172,6 +1172,8 @@ class Rower(models.Model): default='', max_length=200, blank=True, null=True) c2_auto_export = models.BooleanField(default=False) c2_auto_import = models.BooleanField(default=False) + intervals_auto_export = models.BooleanField(default=False) + intervals_auto_import = models.BooleanField(default=False) sporttrackstoken = models.CharField( default='', max_length=200, blank=True, null=True) sporttrackstokenexpirydate = models.DateTimeField(blank=True, null=True) @@ -3827,6 +3829,7 @@ class TombStone(models.Model): uploadedtosporttracks = models.BigIntegerField(default=0) uploadedtotp = models.BigIntegerField(default=0) uploadedtonk = models.BigIntegerField(default=0) + uploadedtointervals = models.BigIntegerField(default=0) @receiver(models.signals.pre_delete, sender=Workout) def create_tombstone_on_delete(sender, instance, **kwargs): @@ -3835,7 +3838,8 @@ def create_tombstone_on_delete(sender, instance, **kwargs): uploadedtoc2=instance.uploadedtoc2, uploadedtostrava=instance.uploadedtostrava, uploadedtotp=instance.uploadedtotp, - uploadedtonk=instance.uploadedtonk + uploadedtonk=instance.uploadedtonk, + uploadedtointervals=instance.uploadedtointervals, ) t.save() diff --git a/rowers/mytypes.py b/rowers/mytypes.py index afc90c8b..b0586308 100644 --- a/rowers/mytypes.py +++ b/rowers/mytypes.py @@ -180,6 +180,41 @@ fitcollection = ( fitmapping = {key: value for key, value in Reverse(fitcollection)} + + +intervalscollection = ( + ('water', 'Rowing'), + ('rower', 'VirtualRow'), + ('skierg', 'NordicSki'), + ('bike', 'Ride'), + ('bikeerg', 'VirtualRide'), + ('dynamic', 'Rowing'), + ('slides', 'Rowing'), + ('paddle', 'StandUpPaddling'), + ('snow', 'NordicSki'), + ('coastal', 'Rowing'), + ('c-boat', 'Rowing'), + ('churchboat', 'Rowing'), + ('Ride', 'Ride'), + ('Run', 'Run'), + ('NordicSki', 'NordicSki'), + ('Swim', 'Swim'), + ('Hike', 'Hike'), + ('Walk', 'Walk'), + ('Canoeing', 'Canoeing'), + ('Crossfit', 'Crossfit'), + ('StandUpPaddling', 'StandUpPaddling'), + ('IceSkate', 'IceSkate'), + ('WeightTraining', 'WeightTraining'), + ('InlineSkate', 'InlineSkate'), + ('Kayaking', 'Kayaking'), + ('Workout', 'Workout'), + ('Yoga', 'Yoga'), + ('other', 'Other'), +) + +intervalsmapping = {key: value for key, value in Reverse(intervalscollection)} + stcollection = ( ('water', 'Rowing'), ('rower', 'Rowing'), @@ -332,6 +367,9 @@ garminmappinginv = {value: key for key, value in Reverse( fitmappinginv = {value: key for key, value in Reverse( fitcollection) if value is not None} +intervalsmappinginv = {value: key for key, value in Reverse( + intervalscollection) if value is not None} + otwtypes = ( 'water', 'coastal', diff --git a/rowers/tasks.py b/rowers/tasks.py index 6fc8793a..36999b19 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -24,7 +24,7 @@ from rowers.courseutils import ( InvalidTrajectoryError ) from rowers.emails import send_template_email -from rowers.mytypes import fitmappinginv +from rowers.mytypes import intervalsmappinginv from rowers.nkimportutils import ( get_nk_summary, get_nk_allstats, get_nk_intervalstats, getdict, strokeDataToDf, add_workout_from_data @@ -3508,11 +3508,11 @@ def handle_intervals_getworkout(rower, intervalstoken, workoutid, debug=False, * title = 'Intervals workout' try: - workouttype = fitmappinginv[data['type']] - print(data['type']) + workouttype = intervalsmappinginv[data['type']] except KeyError: workouttype = 'water' + url = "https://intervals.icu/api/v1/activity/{workoutid}/fit-file".format(workoutid=workoutid) response = requests.get(url, headers=headers) @@ -3535,7 +3535,6 @@ def handle_intervals_getworkout(rower, intervalstoken, workoutid, debug=False, * duration = totaltime_sec_to_string(rowdata.duration) distance = rowdata.df[" Horizontal (meters)"].iloc[-1] except Exception as e: - print(e) return 0 uploadoptions = { @@ -3544,6 +3543,7 @@ def handle_intervals_getworkout(rower, intervalstoken, workoutid, debug=False, * 'boattype': '1x', 'workouttype': workouttype, 'file': fit_filename, + 'intervalsid': intervalsid, 'title': title, 'rpe': 0, 'notes': '', diff --git a/rowers/uploads.py b/rowers/uploads.py index 781271f7..b13881a9 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -146,6 +146,22 @@ def do_sync(w, options, quick=False): except KeyError: pass + do_icu_export = w.user.intervals_auto_export + try: + do_icu_export = options['upload_to_Intervals'] or do_icu_export + except KeyError: + pass + + try: + if options['intervalsid'] != 0 and options['intervalsid'] != '': # pragma: no cover + w.uploadedtointervals = options['intervalsid'] + # upload_to_icu = False + do_icu_export = False + w.save() + record = create_or_update_syncrecord(w.user, w, intervalsid=options['intervalsid']) + except KeyError: + pass + try: if options['nkid'] != 0 and options['nkid'] != '': # pragma: no cover w.uploadedtonk = options['nkid'] @@ -232,14 +248,29 @@ def do_sync(w, options, quick=False): except NoTokenError: # pragma: no cover id = 0 message = "Please connect to Strava first" - except: - e = sys.exc_info()[0] - t = time.localtime() - timestamp = time.strftime('%b-%d-%Y_%H%M', t) - with open('stravalog.log', 'a') as f: - f.write('\n') - f.write(timestamp) - f.write(str(e)) + except Exception as e: + dologging('stravalog.log', e) + + if do_icu_export: + intervals_integration = IntervalsIntegration(w.user.user) + try: + id = intervals_integration.workout_export(w) + dologging( + 'intervals.icu.log', + 'exporting workout {id} as {type}'.format( + id=w.id, + type=w.workouttype, + ) + ) + except NoTokenError: + id = 0 + message = "Please connect to Intervals.icu first" + except Exception as e: + dologging( + 'intervals.icu.log', + e + ) + do_st_export = w.user.sporttracks_auto_export From 2b9e2c1dfd3cf2c571e8740970953d1fb64d2636 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 9 Dec 2024 20:46:10 +0100 Subject: [PATCH 20/32] fixes for RunGap --- rowers/tests/testdata/testdata.tcx.gz | Bin 4001 -> 4002 bytes rowers/views/apiviews.py | 8 +++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index e4b282767cbb0a0b00a3d19988f22f0eb76fbacd..1c63fdbf311e81cba18bddbb4e55981700a69cb1 100644 GIT binary patch literal 4002 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 Ib;N)H0QPu4hX4Qo literal 4001 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 Date: Mon, 9 Dec 2024 21:53:34 +0100 Subject: [PATCH 21/32] import now behaving --- rowers/dataprep.py | 7 ++++ rowers/dataroutines.py | 57 ++++++++++++++++++++++++++++---- rowers/integrations/intervals.py | 17 ++++++++-- rowers/models.py | 6 ++-- rowers/mytypes.py | 1 + rowers/tasks.py | 2 +- rowers/views/importviews.py | 5 ++- 7 files changed, 80 insertions(+), 15 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 8d6ed877..827a9717 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1572,6 +1572,13 @@ def new_workout_from_file(r, f2, # Get workout type from fit & tcx if (fileformat == 'fit'): # pragma: no cover workouttype = get_workouttype_from_fit(f2, workouttype=workouttype) + new_title = get_title_from_fit(f2) + if new_title: + title = new_title + new_notes = get_notes_from_fit(f2) + if new_notes: + notes = new_notes + # if (fileformat == 'tcx'): # workouttype_from_tcx = get_workouttype_from_tcx(f2,workouttype=workouttype) # if workouttype != 'rower' and workouttype_from_tcx not in mytypes.otwtypes: diff --git a/rowers/dataroutines.py b/rowers/dataroutines.py index 61282da7..d34a1a3e 100644 --- a/rowers/dataroutines.py +++ b/rowers/dataroutines.py @@ -1350,6 +1350,39 @@ def handle_nonpainsled(f2, fileformat, summary='', startdatetime='', empowerfirm # Create new workout from file and store it in the database # This routine should be used everywhere in views.py +def get_notes_from_fit(filename): + try: + fitfile = FitFile(filename, check_crc=False) + except FitHeaderError: # pragma: no cover + return '' + + records = fitfile.messages + notes = '' + for record in records: + if record.name == 'session': + try: + notes = ' '.join(record.get_values()['description'].split()) + except KeyError: + pass + + return notes + +def get_title_from_fit(filename): + try: + fitfile = FitFile(filename, check_crc=False) + except FitHeaderError: # pragma: no cover + return '' + + records = fitfile.messages + title = '' + for record in records: + if record.name == 'workout': + try: + title = ' '.join(record.get_values()['wkt_name'].split()) + except KeyError: + pass + + return title def get_workouttype_from_fit(filename, workouttype='water'): try: @@ -1359,17 +1392,27 @@ def get_workouttype_from_fit(filename, workouttype='water'): records = fitfile.messages fittype = 'rowing' + subsporttype = '' for record in records: - if record.name in ['sport', 'lap']: + if record.name in ['sport', 'lap','session']: try: fittype = record.get_values()['sport'].lower() + try: + subsporttype = record.get_values()['sub_sport'].lower() + except KeyError: + subsporttype = '' except (KeyError, AttributeError): # pragma: no cover - return 'water' - try: - workouttype = mytypes.fitmappinginv[fittype] - return workouttype - except KeyError: # pragma: no cover - return workouttype + pass + if subsporttype: + try: + workouttype = mytypes.fitmappinginv[subsporttype] + except KeyError: + pass + else: + try: + workouttype = mytypes.fitmappinginv[fittype] + except KeyError: + pass return workouttype diff --git a/rowers/integrations/intervals.py b/rowers/integrations/intervals.py index 185ef8d9..e1cea0fd 100644 --- a/rowers/integrations/intervals.py +++ b/rowers/integrations/intervals.py @@ -107,8 +107,20 @@ class IntervalsIntegration(SyncIntegration): def get_workout_list(self, *args, **kwargs) -> int: url = self.oauth_data['base_url'] + 'athlete/0/activities?' - startdate = timezone.now() - timedelta(days=365) + startdate = timezone.now() - timedelta(days=30) enddate = timezone.now() + timedelta(days=1) + startdatestring = kwargs.get("startdate","") + enddatestring = kwargs.get("enddate","") + + try: + startdate = arrow.get(startdatestring).datetime + except: + pass + try: + enddate = arrow.get(enddatestring).datetime + except: + pass + url += 'oldest=' + startdate.strftime('%Y-%m-%d') + '&newest=' + enddate.strftime('%Y-%m-%d') headers = { 'accept': '*/*', @@ -122,7 +134,6 @@ class IntervalsIntegration(SyncIntegration): data = response.json() known_interval_ids = get_known_ids(self.rower, 'intervalsid') - workouts = [] for item in data: @@ -145,7 +156,7 @@ class IntervalsIntegration(SyncIntegration): ress = dict(zip(keys, values)) workouts.append(ress) - + return workouts diff --git a/rowers/models.py b/rowers/models.py index 610cd019..259f9f55 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -3697,7 +3697,7 @@ class Workout(models.Model): uploadedtogarmin = models.BigIntegerField(default=0) uploadedtorp3 = models.BigIntegerField(default=0) uploadedtonk = models.BigIntegerField(default=0) - uploadedtointervals = models.BigIntegerField(default=0) + uploadedtointervals = models.CharField(default=None,null=True, max_length=100) forceunit = models.CharField(default='lbs', choices=( ('lbs', 'lbs'), @@ -3829,7 +3829,7 @@ class TombStone(models.Model): uploadedtosporttracks = models.BigIntegerField(default=0) uploadedtotp = models.BigIntegerField(default=0) uploadedtonk = models.BigIntegerField(default=0) - uploadedtointervals = models.BigIntegerField(default=0) + uploadedtointervals = models.CharField(default=None,null=True, max_length=100) @receiver(models.signals.pre_delete, sender=Workout) def create_tombstone_on_delete(sender, instance, **kwargs): @@ -3855,7 +3855,7 @@ class SyncRecord(models.Model): c2id = models.BigIntegerField(unique=True,null=True,default=None) tpid = models.BigIntegerField(unique=True,null=True,default=None) rp3id = models.BigIntegerField(unique=True,null=True,default=None) - intervalsid = models.BigIntegerField(unique=True, null=True, default=None) + intervalsid = models.CharField(unique=True, null=True, default=None, max_length=100) def save(self, *args, **kwargs): if self.workout: diff --git a/rowers/mytypes.py b/rowers/mytypes.py index b0586308..3f19525c 100644 --- a/rowers/mytypes.py +++ b/rowers/mytypes.py @@ -148,6 +148,7 @@ garminmapping = {key: value for key, value in Reverse(garmincollection)} fitcollection = ( ('water', 'rowing'), ('rower', 'rowing'), + ('rower', 'indoor_rowing'), ('skierg', 'cross_country_skiing'), ('bike', 'cycling'), ('bikeerg', 'cycling'), diff --git a/rowers/tasks.py b/rowers/tasks.py index 36999b19..a43a225d 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -3543,7 +3543,7 @@ def handle_intervals_getworkout(rower, intervalstoken, workoutid, debug=False, * 'boattype': '1x', 'workouttype': workouttype, 'file': fit_filename, - 'intervalsid': intervalsid, + 'intervalsid': workoutid, 'title': title, 'rpe': 0, 'notes': '', diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index 486155b1..a02527b0 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -471,7 +471,10 @@ def workout_import_view(request, source='c2'): try: tdict = dict(request.POST.lists()) ids = tdict['workoutid'] - nkids = [int(id) for id in ids] + try: + nkids = [int(id) for id in ids] + except ValueError: + nkids = ids for nkid in nkids: try: _ = integration.get_workout(nkid, startdate=startdate, enddate=enddate) From d93f5de8d16f183d2af5d92b681946edf242da9b Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 9 Dec 2024 22:44:06 +0100 Subject: [PATCH 22/32] export to intervals.icu --- rowers/integrations/intervals.py | 92 +++++++++++++++++++++++++++++- rowers/templates/menu_workout.html | 14 +++++ 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/rowers/integrations/intervals.py b/rowers/integrations/intervals.py index e1cea0fd..2669907f 100644 --- a/rowers/integrations/intervals.py +++ b/rowers/integrations/intervals.py @@ -100,10 +100,98 @@ class IntervalsIntegration(SyncIntegration): return token def createworkoutdata(self, w, *args, **kwargs) -> str: - return NotImplemented + dozip = kwargs.get('dozip', True) + filename = w.csvfilename + try: + row = rowingdata(csvfile=filename) + except IOError: # pragma: no cover + data = dataprep.read_df_sql(w.id) + try: + datalength = len(data) + except AttributeError: + datalength = 0 + + if datalength == 0: + data.rename(columns=columndict, inplace=True) + _ = data.to_csv(w.csvfilename+'.gz', index_label='index', compression='gzip') + try: + row = rowingdata(csvfile=filename) + except IOError: # pragma: no cover + return '' # pragma: no cover + else: + return '' + + tcxfilename = w.csvfilename[:-4] + '.tcx' + try: + newnotes = w.notes + '\n from'+w.workoutsource+' via rowsandall.com' + except TypeError: + newnotes = 'from'+w.workoutsource+' via rowsandall.com' + + row.exporttotcx(tcxfilename, notes=newnotes) + if dozip: + gzfilename = tcxfilename + '.gz' + try: + with open(tcxfilename, 'rb') as inF: + s = inF.read() + with gzip.GzipFile(gzfilename, 'wb') as outF: + outF.write(s) + try: + os.remove(tcxfilename) + except WindowsError: # pragma: no cover + pass + except FileNotFoundError: + return '' + + return gzfilename + + return tcxfilename + + def workout_export(self, workout, *args, **kwargs) -> str: - return NotImplemented + token = self.open() + + filename = self.createworkoutdata(workout) + if not filename: + return 0 + + params = { + 'name': workout.name, + 'description': workout.notes, + } + + + authorizationstring = str('Bearer ' + token) + # headers with authorization string and content type multipart/form-data + headers = { + 'Authorization': authorizationstring, + } + + url = "https://intervals.icu/api/v1/athlete/{athleteid}/activities".format(athleteid=0) + + with open(filename, 'rb') as f: + files = {'file': f} + response = requests.post(url, params=params, headers=headers, files=files) + + if response.status_code not in [200, 201]: + dologging('intervals.icu.log', response.reason) + return 0 + + id = response.json()['id'] + # set workout type to workouttype + url = "https://intervals.icu/api/v1/activity/{activityid}".format(activityid=id) + + thetype = mytypes.intervalsmapping[workout.workouttype] + response = requests.put(url, headers=headers, json={'type': thetype}) + if response.status_code not in [200, 201]: + return 0 + + workout.uploadedtointervals = id + workout.save() + + os.remove(filename) + + return id def get_workout_list(self, *args, **kwargs) -> int: url = self.oauth_data['base_url'] + 'athlete/0/activities?' diff --git a/rowers/templates/menu_workout.html b/rowers/templates/menu_workout.html index f61797f6..ea138baf 100644 --- a/rowers/templates/menu_workout.html +++ b/rowers/templates/menu_workout.html @@ -231,6 +231,20 @@ {% endif %} +
  • + {% if workout.uploadedtointervals and workout.uploadedtointervals != '0' %} + + Intervals.icu + + {% elif user.rower.intervals_token == None or user.rower.intervals_token == '' %} + + Connect to Intervals.icu + + {% else %} + + Intervals.icu + + {% endif %}
  • CSV From fc52491e8a85b75f06e78896b392ebc8a331f18b Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 10 Dec 2024 08:00:41 +0100 Subject: [PATCH 23/32] fix --- rowers/integrations/c2.py | 2 +- rowers/integrations/nk.py | 2 +- rowers/integrations/rp3.py | 2 +- rowers/integrations/strava.py | 2 +- rowers/integrations/trainingpeaks.py | 2 +- rowers/tests/testdata/testdata.tcx.gz | Bin 4002 -> 4001 bytes 6 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rowers/integrations/c2.py b/rowers/integrations/c2.py index 2a4a57ab..c2d21332 100644 --- a/rowers/integrations/c2.py +++ b/rowers/integrations/c2.py @@ -63,7 +63,7 @@ class C2Integration(SyncIntegration): 'client_id': C2_CLIENT_ID, 'client_secret': C2_CLIENT_SECRET, 'redirect_uri': C2_REDIRECT_URI, - 'autorization_uri': "https://log.concept2.com/oauth/authorize", + 'authorization_uri': "https://log.concept2.com/oauth/authorize", 'content_type': 'application/x-www-form-urlencoded', 'tokenname': 'c2token', 'refreshtokenname': 'c2refreshtoken', diff --git a/rowers/integrations/nk.py b/rowers/integrations/nk.py index 960b2f51..a26a7cc9 100644 --- a/rowers/integrations/nk.py +++ b/rowers/integrations/nk.py @@ -35,7 +35,7 @@ class NKIntegration(SyncIntegration): 'client_id': NK_CLIENT_ID, 'client_secret': NK_CLIENT_SECRET, 'redirect_uri': NK_REDIRECT_URI, - 'autorization_uri': NK_OAUTH_LOCATION+"/oauth/authorize", + 'authorization_uri': NK_OAUTH_LOCATION+"/oauth/authorize", 'content_type': 'application/json', 'tokenname': 'nktoken', 'refreshtokenname': 'nkrefreshtoken', diff --git a/rowers/integrations/rp3.py b/rowers/integrations/rp3.py index 245c7615..bdbae35e 100644 --- a/rowers/integrations/rp3.py +++ b/rowers/integrations/rp3.py @@ -30,7 +30,7 @@ class RP3Integration(SyncIntegration): 'client_id': RP3_CLIENT_ID, 'client_secret': RP3_CLIENT_SECRET, 'redirect_uri': RP3_REDIRECT_URI, - 'autorization_uri': "https://rp3rowing-app.com/oauth/authorize?", + 'authorization_uri': "https://rp3rowing-app.com/oauth/authorize?", 'content_type': 'application/x-www-form-urlencoded', # 'content_type': 'application/json', 'tokenname': 'rp3token', diff --git a/rowers/integrations/strava.py b/rowers/integrations/strava.py index b78281a0..8df2cb31 100644 --- a/rowers/integrations/strava.py +++ b/rowers/integrations/strava.py @@ -89,7 +89,7 @@ class StravaIntegration(SyncIntegration): 'client_id': STRAVA_CLIENT_ID, 'client_secret': STRAVA_CLIENT_SECRET, 'redirect_uri': STRAVA_REDIRECT_URI, - 'autorization_uri': "https://www.strava.com/oauth/authorize", + 'authorization_uri': "https://www.strava.com/oauth/authorize", 'content_type': 'application/json', 'tokenname': 'stravatoken', 'refreshtokenname': 'stravarefreshtoken', diff --git a/rowers/integrations/trainingpeaks.py b/rowers/integrations/trainingpeaks.py index 14e3307a..404801de 100644 --- a/rowers/integrations/trainingpeaks.py +++ b/rowers/integrations/trainingpeaks.py @@ -41,7 +41,7 @@ class TPIntegration(SyncIntegration): 'client_id': TP_CLIENT_ID, 'client_secret': TP_CLIENT_SECRET, 'redirect_uri': TP_REDIRECT_URI, - 'autorization_uri': "https://oauth.trainingpeaks.com/oauth/authorize?", + 'authorization_uri': "https://oauth.trainingpeaks.com/oauth/authorize?", 'content_type': 'application/x-www-form-urlencoded', 'tokenname': 'tptoken', 'refreshtokenname': 'tprefreshtoken', diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 1c63fdbf311e81cba18bddbb4e55981700a69cb1..44ca7da185282a4134935f7eb23bb2dcbe772b58 100644 GIT binary patch literal 4001 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 Ib;N)H0QPu4hX4Qo From ed3bf035399dd5d786aed13609cb80431949a3e8 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 10 Dec 2024 08:02:55 +0100 Subject: [PATCH 24/32] changing return status: --- rowers/views/apiviews.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rowers/views/apiviews.py b/rowers/views/apiviews.py index 2a478053..51c4cfb5 100644 --- a/rowers/views/apiviews.py +++ b/rowers/views/apiviews.py @@ -575,7 +575,7 @@ def strokedata_fit(request): return JsonResponse({ "status": "error", "message": f"An error occurred while saving the FIT file: {str(e)}" - }, status=500) + }, status=400) try: # Parse the FIT file @@ -585,7 +585,7 @@ def strokedata_fit(request): return JsonResponse({ "status": "error", "message": f"An error occurred while parsing the FIT file: {str(e)}" - }, status=500) + }, status=422) rowdata = rowingdata(df=row.df) From 2f5cd1b84474d36ccc68727bcb6dd3ccd2191377 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 10 Dec 2024 08:06:07 +0100 Subject: [PATCH 25/32] returning better code --- rowers/views/apiviews.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rowers/views/apiviews.py b/rowers/views/apiviews.py index 51c4cfb5..de8cc5be 100644 --- a/rowers/views/apiviews.py +++ b/rowers/views/apiviews.py @@ -601,6 +601,7 @@ def strokedata_fit(request): dologging('apilog.log','FIT error to get time') dologging('apilog.log',e) _ = myqueue(queuehigh, handle_sendemail_unrecognized, fit_filename, "fit parser") + return HttpResponse(status=422) w = Workout.objects.create(user=request.user.rower, duration=duration, From 5db98f034f7a78e950c16b00a034f445938f0b2f Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 10 Dec 2024 17:44:44 +0100 Subject: [PATCH 26/32] tested --- rowers/tests/testdata/testdata.tcx.gz | Bin 4001 -> 4000 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 44ca7da185282a4134935f7eb23bb2dcbe772b58..4ab2f8bd4647adef840c754fefc2d20fa0e34e9e 100644 GIT binary patch literal 4000 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 GfB^t2@GX7- literal 4001 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 Date: Tue, 10 Dec 2024 20:00:52 +0100 Subject: [PATCH 27/32] intervals auto im & export --- rowers/forms.py | 3 ++ rowers/integrations/intervals.py | 28 +++++++++++++-- rowers/management/commands/getsyncids.py | 6 ++-- rowers/management/commands/processemail.py | 11 ++++++ rowers/models.py | 4 ++- rowers/templates/rower_exportsettings.html | 3 ++ rowers/uploads.py | 42 +++++++++++++--------- rowers/views/workoutviews.py | 11 ++++++ 8 files changed, 87 insertions(+), 21 deletions(-) diff --git a/rowers/forms.py b/rowers/forms.py index fa3f1b4b..0ebc5fb3 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -554,6 +554,9 @@ class UploadOptionsForm(forms.Form): upload_to_TrainingPeaks = forms.BooleanField(initial=False, required=False, label='Export to TrainingPeaks') + upload_to_Intervals = forms.BooleanField(initial=False, + required=False, + label='Export to Intervals') # do_physics = forms.BooleanField(initial=False,required=False,label='Power Estimate (OTW)') makeprivate = forms.BooleanField(initial=False, required=False, label='Make Workout Private') diff --git a/rowers/integrations/intervals.py b/rowers/integrations/intervals.py index 2669907f..4437019e 100644 --- a/rowers/integrations/intervals.py +++ b/rowers/integrations/intervals.py @@ -183,6 +183,7 @@ class IntervalsIntegration(SyncIntegration): thetype = mytypes.intervalsmapping[workout.workouttype] response = requests.put(url, headers=headers, json={'type': thetype}) + if response.status_code not in [200, 201]: return 0 @@ -260,8 +261,31 @@ class IntervalsIntegration(SyncIntegration): self.rower.intervals_token, id) - def get_workouts(workout, *args, **kwargs) -> list: - return NotImplemented + return 1 + + def get_workouts(self, *args, **kwargs): + startdate = timezone.now() - timedelta(days=7) + enddate = timezone.now() + timedelta(days=1) + startdatestring = kwargs.get(startdate,"") + enddatestring = kwargs.get(enddate,"") + + try: + startdate = arrow.get(startdatestring).datetime + except: + pass + try: + enddate = arrow.get(enddatestring).datetime + except: + pass + + count = 0 + workouts = self.get_workout_list(startdate=startdate, enddate=enddate) + for workout in workouts: + if workout['new'] == 'NEW': + self.get_workout(workout['id']) + count +=1 + + return count def make_authorization_url(self, *args, **kwargs): return super(IntervalsIntegration, self).make_authorization_url(*args, **kwargs) diff --git a/rowers/management/commands/getsyncids.py b/rowers/management/commands/getsyncids.py index a2f9bf75..806a7218 100644 --- a/rowers/management/commands/getsyncids.py +++ b/rowers/management/commands/getsyncids.py @@ -24,7 +24,8 @@ class Command(BaseCommand): record.sporttracksid = w.uploadedtosporttracks if w.uploadedtoc2: record.c2id = w.uploadedtoc2 - + if w.uploadedtointervals: + record.intervalsid = w.uploadedtointervals try: record.save() except IntegrityError: @@ -52,7 +53,8 @@ class Command(BaseCommand): record.sporttracksid = w.uploadedtosporttracks if w.uploadedtoc2: record.c2id = w.uploadedtoc2 - + if w.uploadedtointervals: + record.intervalsid = w.uploadedtointervals try: record.save() except IntegrityError: diff --git a/rowers/management/commands/processemail.py b/rowers/management/commands/processemail.py index 6d12ff71..be02ab17 100644 --- a/rowers/management/commands/processemail.py +++ b/rowers/management/commands/processemail.py @@ -117,5 +117,16 @@ class Command(BaseCommand): lines = traceback.format_exception(exc_type, exc_value, exc_traceback) dologging('processemail.log', ''.join('!! ' + line for line in lines)) + rowers = Rower.objects.filter(intervals_auto_import=True) + for r in rowers: + try: + if user_is_not_basic(r.user) or user_is_coachee(r.user): + intervals_integration = IntervalsIntegration(r.user) + _ = intervals_integration.get_workouts() + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + lines = traceback.format_exception(exc_type, exc_value, exc_traceback) + dologging('processemail.log', ''.join('!! ' + line for line in lines)) + self.stdout.write(self.style.SUCCESS( 'Successfully processed email attachments')) diff --git a/rowers/models.py b/rowers/models.py index 259f9f55..f4715081 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -4557,7 +4557,9 @@ class RowerExportForm(ModelForm): 'strava_auto_import', 'strava_auto_delete', 'trainingpeaks_auto_export', - 'rp3_auto_import' + 'rp3_auto_import', + 'intervals_auto_import', + 'intervals_auto_export', ] # Simple form to set rower's Functional Threshold Power diff --git a/rowers/templates/rower_exportsettings.html b/rowers/templates/rower_exportsettings.html index 866a771a..3ad0019d 100644 --- a/rowers/templates/rower_exportsettings.html +++ b/rowers/templates/rower_exportsettings.html @@ -37,6 +37,9 @@ {% if rower.rojabo_token is not None and rower.rojabo_token != '' %} Rojabo {% endif %} + {% if rower.intervals_token is not None and rower.intervals_token != '' %} + Intervals.icu + {% endif %}

    {% if form.errors %} diff --git a/rowers/uploads.py b/rowers/uploads.py index b13881a9..bb587c21 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -130,11 +130,14 @@ def make_plot(r, w, f1, f2, plottype, title, imagename='', plotnr=0): def do_sync(w, options, quick=False): - do_strava_export = w.user.strava_auto_export - try: - do_strava_export = options['upload_to_Strava'] or do_strava_export - except KeyError: - pass + do_strava_export = False + if w.user.strava_auto_export is True: + do_strava_export = True + else: + try: + do_strava_export = options['upload_to_Strava'] or do_strava_export + except KeyError: + pass try: if options['stravaid'] != 0 and options['stravaid'] != '': # pragma: no cover @@ -146,11 +149,15 @@ def do_sync(w, options, quick=False): except KeyError: pass - do_icu_export = w.user.intervals_auto_export - try: - do_icu_export = options['upload_to_Intervals'] or do_icu_export - except KeyError: - pass + do_icu_export = False + if w.user.intervals_auto_export is True: + do_icu_export = True + else: + try: + do_icu_export = options['upload_to_Intervals'] + except KeyError: + pass + try: if options['intervalsid'] != 0 and options['intervalsid'] != '': # pragma: no cover @@ -193,11 +200,14 @@ def do_sync(w, options, quick=False): except KeyError: pass - do_c2_export = w.user.c2_auto_export - try: - do_c2_export = options['upload_to_C2'] or do_c2_export - except KeyError: - pass + do_c2_export = False + if w.user.c2_auto_export is True: + do_c2_export = True + else: + try: + do_c2_export = options['upload_to_C2'] or do_c2_export + except KeyError: + pass try: if options['c2id'] != 0 and options['c2id'] != '': # pragma: no cover @@ -266,7 +276,7 @@ def do_sync(w, options, quick=False): id = 0 message = "Please connect to Intervals.icu first" except Exception as e: - dologging( + dologging( 'intervals.icu.log', e ) diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index a250e4aa..14112726 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -5247,6 +5247,7 @@ def workout_upload_view(request, upload_to_strava = uploadoptions.get('upload_to_Strava', False) upload_to_st = uploadoptions.get('upload_to_SportTracks', False) upload_to_tp = uploadoptions.get('upload_to_TrainingPeaks', False) + upload_to_intervals = uploadoptions.get('upload_to_Intervals', False) response = {} if request.method == 'POST': @@ -5296,6 +5297,7 @@ def workout_upload_view(request, upload_to_strava = optionsform.cleaned_data['upload_to_Strava'] upload_to_st = optionsform.cleaned_data['upload_to_SportTracks'] upload_to_tp = optionsform.cleaned_data['upload_to_TrainingPeaks'] + upload_to_intervals = optionsform.cleaned_data['upload_to_Intervals'] makeprivate = optionsform.cleaned_data['makeprivate'] landingpage = optionsform.cleaned_data['landingpage'] raceid = optionsform.cleaned_data['raceid'] @@ -5313,6 +5315,7 @@ def workout_upload_view(request, 'upload_to_Strava': upload_to_strava, 'upload_to_SportTracks': upload_to_st, 'upload_to_TrainingPeaks': upload_to_tp, + 'upload_to_Intervals': upload_to_intervals, 'landingpage': landingpage, 'boattype': boattype, 'rpe': rpe, @@ -5447,6 +5450,14 @@ def workout_upload_view(request, message = "Please connect to TrainingPeaks first" messages.error(request, message) + if (upload_to_intervals): + intervals_integration = IntervalsIntegration(request.user) + try: + id = intervals_integration.workout_export(w) + except NoTokenError: + message = "Please connect to Intervals.icu first" + messages.error(request, message) + if int(registrationid) < 0: # pragma: no cover race = VirtualRace.objects.get(id=-int(registrationid)) if race.sessiontype == 'race': From 8327e51841804638b4000790ca6dd86ee5199f66 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 11 Dec 2024 08:07:13 +0100 Subject: [PATCH 28/32] testing --- rowers/templates/rower_exportsettings.html | 4 ++-- rowers/tests/testdata/testdata.tcx.gz | Bin 4000 -> 3999 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rowers/templates/rower_exportsettings.html b/rowers/templates/rower_exportsettings.html index 3ad0019d..b6aae035 100644 --- a/rowers/templates/rower_exportsettings.html +++ b/rowers/templates/rower_exportsettings.html @@ -32,10 +32,10 @@ Strava, {% endif %} {% if rower.rp3token is not None and rower.rp3token != '' %} - RP3 + RP3, {% endif %} {% if rower.rojabo_token is not None and rower.rojabo_token != '' %} - Rojabo + Rojabo, {% endif %} {% if rower.intervals_token is not None and rower.intervals_token != '' %} Intervals.icu diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 4ab2f8bd4647adef840c754fefc2d20fa0e34e9e..6ae0e30902e4a847a9bea105dfbe010424bba57f 100644 GIT binary patch literal 3999 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 F0RYMsI8guq literal 4000 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 GfB^t2@GX7- From 3e9c23b03f0c26299591793687bc2af09669784c Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 11 Dec 2024 19:23:44 +0100 Subject: [PATCH 29/32] temp logging --- rowers/integrations/intervals.py | 3 ++- rowers/integrations/trainingpeaks.py | 2 +- rowers/mytypes.py | 33 ++++++++++++++++++++++++++++ rowers/views/workoutviews.py | 2 ++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/rowers/integrations/intervals.py b/rowers/integrations/intervals.py index 4437019e..b55a50a4 100644 --- a/rowers/integrations/intervals.py +++ b/rowers/integrations/intervals.py @@ -128,7 +128,7 @@ class IntervalsIntegration(SyncIntegration): except TypeError: newnotes = 'from'+w.workoutsource+' via rowsandall.com' - row.exporttotcx(tcxfilename, notes=newnotes) + row.exporttotcx(tcxfilename, notes=newnotes, sport=mytypes.intervalsmapping[w.workouttype]) if dozip: gzfilename = tcxfilename + '.gz' try: @@ -181,6 +181,7 @@ class IntervalsIntegration(SyncIntegration): # set workout type to workouttype url = "https://intervals.icu/api/v1/activity/{activityid}".format(activityid=id) + thetype = mytypes.intervalsmapping[workout.workouttype] response = requests.put(url, headers=headers, json={'type': thetype}) diff --git a/rowers/integrations/trainingpeaks.py b/rowers/integrations/trainingpeaks.py index 404801de..efe98532 100644 --- a/rowers/integrations/trainingpeaks.py +++ b/rowers/integrations/trainingpeaks.py @@ -66,7 +66,7 @@ class TPIntegration(SyncIntegration): except TypeError: newnotes = 'from '+w.workoutsource+' via rowsandall.com' - row.exporttotcx(tcxfilename, notes=newnotes) + row.exporttotcx(tcxfilename, notes=newnotes, sport=tpmapping(w.workouttype)) return tcxfilename diff --git a/rowers/mytypes.py b/rowers/mytypes.py index 3f19525c..194793fe 100644 --- a/rowers/mytypes.py +++ b/rowers/mytypes.py @@ -181,7 +181,40 @@ fitcollection = ( fitmapping = {key: value for key, value in Reverse(fitcollection)} +tcxcollection = ( + ('water', 'Rowing'), + ('rower', 'Rowing'), + ('skierg', 'CrossCountrySkiing'), + ('bike', 'Biking'), + ('bikeerg', 'Biking'), + ('dynamic', 'Rowing'), + ('slides', 'Rowing'), + ('paddle', 'Other'), + ('snow', 'CrossCountrySkiing'), + ('coastal', 'Rowing'), + ('c-boat', 'Rowing'), + ('churchboat', 'Rowing'), + ('Ride', 'Biking'), + ('Run', 'Running'), + ('NordicSki', 'CrossCountrySkiing'), + ('Swim', 'Swimming'), + ('Hike', 'Hiking'), + ('Walk', 'Walking'), + ('Canoeing', 'Other'), + ('Crossfit', 'Other'), + ('StandUpPaddling', 'Other'), + ('IceSkate', 'Other'), + ('WeightTraining', 'Other'), + ('InlineSkate', 'Other'), + ('Kayaking', 'Other'), + ('Workout', 'Other'), + ('Yoga', 'Other'), + ('other', 'Other'), +) +tcxmapping = {key: value for key, value in Reverse(tcxcollection)} + +tcxmappinginv = {value: key for key, value in Reverse(tcxcollection) if value is not None} intervalscollection = ( ('water', 'Rowing'), diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 14112726..a27e3887 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -4971,6 +4971,8 @@ def workout_upload_api(request): message = {'status': 'false', 'message': 'could not find file'} return JSONResponse(status=400, data=message) + dologging('own_api.log','-temp-') + dologging('own_api.log',post_data) # sync related IDs sporttracksid = post_data.get('sporttracksid','') From 8c9347943c15037ead8a0a9cc772de25c6baa2d9 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 11 Dec 2024 19:37:23 +0100 Subject: [PATCH 30/32] more logggin --- rowers/uploads.py | 1 + rowers/views/workoutviews.py | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rowers/uploads.py b/rowers/uploads.py index bb587c21..4337e1c1 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -158,6 +158,7 @@ def do_sync(w, options, quick=False): except KeyError: pass + dologging("uploads.log", "do_icu_export: {do_icu_export}".format(do_icu_export=do_icu_export) try: if options['intervalsid'] != 0 and options['intervalsid'] != '': # pragma: no cover diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index a27e3887..14112726 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -4971,8 +4971,6 @@ def workout_upload_api(request): message = {'status': 'false', 'message': 'could not find file'} return JSONResponse(status=400, data=message) - dologging('own_api.log','-temp-') - dologging('own_api.log',post_data) # sync related IDs sporttracksid = post_data.get('sporttracksid','') From 3f53612e2ab31565584eb78560c04883f5b34a55 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 11 Dec 2024 19:39:15 +0100 Subject: [PATCH 31/32] fix --- rowers/uploads.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rowers/uploads.py b/rowers/uploads.py index 4337e1c1..935dd8ef 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -158,7 +158,7 @@ def do_sync(w, options, quick=False): except KeyError: pass - dologging("uploads.log", "do_icu_export: {do_icu_export}".format(do_icu_export=do_icu_export) + dologging("uploads.log", "do_icu_export: {do_icu_export}".format(do_icu_export=do_icu_export)) try: if options['intervalsid'] != 0 and options['intervalsid'] != '': # pragma: no cover From 1e17be5cc951f4950f1c2485aa45c90a7571649b Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 11 Dec 2024 21:25:14 +0100 Subject: [PATCH 32/32] fi --- rowers/integrations/intervals.py | 3 +++ rowers/uploads.py | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/rowers/integrations/intervals.py b/rowers/integrations/intervals.py index b55a50a4..4e0ac680 100644 --- a/rowers/integrations/intervals.py +++ b/rowers/integrations/intervals.py @@ -150,6 +150,7 @@ class IntervalsIntegration(SyncIntegration): def workout_export(self, workout, *args, **kwargs) -> str: token = self.open() + dologging('intervals.icu.log', "Exporting workout {id}".format(id=workout.id)) filename = self.createworkoutdata(workout) if not filename: @@ -192,6 +193,8 @@ class IntervalsIntegration(SyncIntegration): workout.save() os.remove(filename) + + dologging('intervals.icu.log', "Exported workout {id}".format(id=workout.id)) return id diff --git a/rowers/uploads.py b/rowers/uploads.py index 935dd8ef..71f07553 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -158,7 +158,7 @@ def do_sync(w, options, quick=False): except KeyError: pass - dologging("uploads.log", "do_icu_export: {do_icu_export}".format(do_icu_export=do_icu_export)) + #dologging("uploads.log", "do_icu_export: {do_icu_export}".format(do_icu_export=do_icu_export)) try: if options['intervalsid'] != 0 and options['intervalsid'] != '': # pragma: no cover @@ -275,6 +275,7 @@ def do_sync(w, options, quick=False): ) except NoTokenError: id = 0 + dologging('intervals.icu.log','NoTokenError') message = "Please connect to Intervals.icu first" except Exception as e: dologging(