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 @@

+{% 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
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
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
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
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">

+
{% 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
zcmV;S4_@#eiwFo3=T~O}|8!+@bYx+4VJ>uIcmVC4NpBoC7J%>m6@m`QVG#CP__!#t
z0>{o^4A`C^F*3OgDpE)88L1_x%iF&nvfGhmTZQCFQv|C(9}IPMZCzhI^6fnQ?%ny>
z-kassW_7WCxQ_<*_r5!NaQO17Tdh~?)5ptozr1?V_1$mXX1SMkUT+@mzv}zTgT>n~ST{1p(mV*XPfE-k#!{)q2x+>*HlQYO^}no%h+rao2Bu?VWC5Pk+=K
zGVeAge}3TKyZ&)^c5$^@ZWeFw&-eem>yLN)FRw3!f9+C(fbM$e?l_ww1sk9+@t?+7s*F0Ma)+~H9YweEEJk7c_1pSphe{pI=g)$HG2reAWs
z`RV%mW!GOWukG5~cGLgOBa`Qo+EYkx%BFv9*_xBBoSF6+0bZg80)y2ut
z^KSjRJ4+Nl*?M#D?)bl--2HaT<;7~<-`t$PNbkU3co(<3eR||)uY?#o{F-bJxF>;|
z6v%%;VMpS21fM)$xaIk7ceozCHeX!!<&VGq<(c5tG5qs0rgQ$Q>-!`&@o=&G>+@?a
z(nUZ2dAHwUei3fNtEJ9hlC+CeP)9a64ea?rSHzuMMcfla1Q!(CDd|lGxre)Rr@G|b
zN=4kAAx70GpN0r7$UV-6yR#K>k4fIGcn$YhQr;P6!`)ZJ-O_fPcM9${7%Ipe@4+3b
z;vS$P?vl7Cq0(sc-nfZyuS?zoSH#_$;K6D1dFM)+aZK~!?(5+$V0=KUk#{dfCc?e4
zalRruPS`}SQNuk*N&9_H@*XPU?u-Khjb0a}s6Ia*c}J*7v6E<+b#7XOvgG+53jEfjmZ
zHS;{#vgGZI$X67x;a~v3i-x>F$>_YjkKdk~RX0RF$**;&O2ZDdBl$Rkchw{KC}Ve-y+!JvuKGGS4Beoo{ovgfmf##S}YGoy(UA&+gI
zznwhi+*<}DjVC9)C?&J5t!sY!QOJt{hM
zIOpCvkEj{#1z|EW-|YEe^3hO$7*ynA)9t4pu@TDMQdCh|VQ9Mj^krVG2}!qC$-FI_
zbsbwR?I`5E5!OX)M9PwHKD-gg+XUO7x2mjbagF?4$=iy^lL=l|T_qkT6Q6G~KTKYX
zB~(>cNhn)a*Lq-%Lp~TnRCP{}ShmK-H{E^=@(3m(vBrDr09)?u^kp8|NFdTgX&p|7
zJU36yAbFRwu2r279br-3eoo|T8ttP2#Gr}KJEo#l)V{^%#~`0`ZvzHR-&<#?XzuNt
z$X8^~lQra!Rr9>iWO8r0)z1%-_XaJJYP5G$)SjOac}EqI&z%#9HT~_K=c4ocoXA(C
z+b3;}BdS&{bAelwb_V3d0Enu~xr^MQw9_B$*&7jECqxg8{9Vacq}y9C>_z3t@n}nG
zc=yV~YZ~4#dCuKWRo+{lEWy|^Fegu5jJFOou{xi0gMzU-!5P`}6~*UmFcuj#IXOPP
zEp{U0YxCiSddLgrT3Xeb7G8?h&(BHbYtrz9jTb_V56?SS(r-VjdA=fhKFKdfQq|aa
z?^;FW9m!V|rIl!a2~?wfaFfyPoA-8ryc_@;uk_*hSacQgS;@RqMBW+;qLTRlMc1O9
zmCU<}$a{l8pt0%#hRMi$BR@<&8kYup&1fGe6t(B)G}?!H$RinRF>11|1IH%wcO)Mx
zA}D!!86pn>)pWB%dvJSnoMQuB2bNwjjt+9eCA1;EICiQnjPZgo}xkZ*o
z75d;NBlVS`XIBsUWT)9cU{&a&FRJFvX~4&d&~uvW2~=}ELYNHt+6MfZq}~|@B-LDx
zShn0|PUyKJ^f7DrQ783fS1oMl$3dSvp*mJ&W?`DKnub3E^pXdBRmc`msA#l)PHJ97
z#vKPk9)n85N7uZ0cQx)pJ?PWe4KDY`)1dc7`{3RyBNLi&H;CRE0Aiig2Rj+`*o?bD
z^gf~2HPOh~Tt(4yLq7`oXrfiRbO>BgCEqW^3
zDs4_u4;7&gMub!iu#u8Q=o|WJyL5c+jA@;S%DAJXAjm}8=U`iweh|Gi>~-yP^1>LC
z>73N;`eF3mP>`S-@I4eQtjDJ2je#DM04odbkOEGoBQCbI%t7>Q(CNBnA;qE#m(FUy
zr;5-!1D13dxePp+HE!BmKa4(@D9Y*^MqAXS)8_h7&=Z8L43T{-+Bl7xT|Wx?Xegr9Y51XR_=cM|Zw&O7a{nxyH;-d%YTon*
zd@BY-S$Jg;CKIo(Eg8F_psh_B8&Zra^h9m0pFVm46O{`Wqh%@@xobZBanQ4g4oQdJ
z@?@4bYmVGu^xKw+UZv()vCXA3eMj!LWg>drT<>Hu30f^Ja{ztVwoC-wk~e6*G~;gS
zc74b#6RilU9Jw~M>YKZw4;7&gxr3IjtA>qb!#CUp{4vlY8fI}SsTU}_Ts_Z7&4Y^2
z+ihzFm6|7o+bGSczTQ@Z-W#&Ypsg?z_2$_&;E#cxz#uWQ3cZENtZmr5dBf
z*C&gh6Rs-t5q0Pt6*cZ!SB-Jdhb;A8H{g4ojMTRQe-J&R3BtN~y#!lS!*4;`
zanM`i5K+}tL!xcoyy-h~*&EMfRY6+^ZZfGFP0brbpX@a2P?x3S(6s@7>bZFdJsY9y
zq|u6Bo!HcG?jow1M;Ej8#lv;lwmj$9iPdLmWfm9ud&m9{NQXAr%RVXY6}IcRhJ
z4A6@q(yDnLT1M{F3$H?MnTTnd4t>DMG*oG7-T?ZTTP6Zx)YIn*BrT1cj?63G7+?E
z+IsINGuKlK+76=6Mb-?e@Qn|?+4VC(AB`mIPAB!zPsXmNrsfTyXEI`~E_@RpG`oHV
z=p`3kfet+uMW2@nY6JcV=z{@9T|fMgllLcro|-pr2z_438ZhY4bDRwNwtoFEdNx5w
z7r9F>N=XerccN(MM?mk4XB$;6o#3#fOJ`Q-r6Tk(uW1W9srOiP!1t{LV+`~{##s!i
zES(UFR@&YReXF?}MlZSgCa5xULo8Zpd#?e%_0kzeAM%>Ey2xFGqKlo)O2e-uOGjY4
zk~N@LIdUV)WL!GX`sNLy->zh>TjwrP*`O`7xqcM%K3Cr;(X*e->XvP;A4H#5vSuWe
zH!oUWwEBix-@H-K^L7z)m2np(w$&{s?#;{ST`s&*qIa>V)VD^da_p%aIrh!!R}0d{KowG`qOIn
z{o&)Q#PQ)%x_L>$`N`ZufR2Dj$zKeDu11b#Zm$
zHFe{r((-S@9oXD8P`_m}iOrbBN$oDW-`cmGM3%+7+FpTFE~
zwN9J8eB5ul;rh{jcK*Yc>86i
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(