Compare commits

..

No commits in common. "master" and "recaptcha" have entirely different histories.

17 changed files with 86 additions and 693 deletions

View file

@ -1,2 +1 @@
.git .git
.env

3
.gitignore vendored
View file

@ -44,6 +44,3 @@ secret-key
!.gitkeep !.gitkeep
*.orig *.orig
.vscode/settings.json .vscode/settings.json
2024-*
2025-*
2023-*

View file

@ -1,5 +1,4 @@
# FROM python:3.10.0-alpine3.15 FROM python:3.10.0-alpine3.15
FROM python:3.5-alpine3.12
WORKDIR /usr/src/app WORKDIR /usr/src/app
@ -8,25 +7,12 @@ RUN apk add --update --no-cache \
build-base \ build-base \
openldap-dev \ openldap-dev \
python3-dev \ python3-dev \
postgresql-dev \ libpq-dev \
jpeg-dev \
libxml2-dev \
libxslt-dev \
libmemcached-dev \
zlib-dev \
&& rm -rf /var/cache/apk/* && rm -rf /var/cache/apk/*
## For alpine 3.15 replace postgresql-dev with libpq-dev
# FIX https://github.com/python-ldap/python-ldap/issues/432 # FIX https://github.com/python-ldap/python-ldap/issues/432
RUN echo 'INPUT ( libldap.so )' > /usr/lib/libldap_r.so RUN echo 'INPUT ( libldap.so )' > /usr/lib/libldap_r.so
COPY requirements.txt ./ COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
# Pillow seems to need LIBRARY_PATH set as follows: (see: https://github.com/python-pillow/Pillow/issues/1763#issuecomment-222383534)
RUN LIBRARY_PATH=/lib:/usr/lib /bin/sh -c "pip install --no-cache-dir -r requirements.txt"
COPY ./ . COPY ./ .
COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh" ]

View file

@ -1,23 +0,0 @@
#!/bin/sh
if [ $# -lt 1 ]; then
echo "$0 imageversion [push]"
echo "Version could be: $(git describe --always)"
echo "If push is specified, also push to our harbor"
exit 1
fi
tagprefix=harbor.k8s.ungleich.ch/ungleich-public/dynamicweb
version=$1; shift
tag=${tagprefix}:${version}
set -ex
docker build -t "${tag}" .
push=$1; shift
if [ "$push" ]; then
docker push "${tag}"
fi

View file

@ -1,9 +1,8 @@
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from opennebula_api.models import OpenNebulaManager from opennebula_api.models import OpenNebulaManager
from datacenterlight.models import VMTemplate from datacenterlight.models import VMTemplate
from datacenterlight.cms_models import DCLCalculatorPluginModel
from membership.models import CustomUser from membership.models import CustomUser
from utils.tasks import send_plain_email_task
from django.conf import settings from django.conf import settings
from time import sleep from time import sleep
import datetime import datetime
@ -22,7 +21,6 @@ class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
result_dict = {} result_dict = {}
error_dict = {}
user_email = options['user_email'] if 'user_email' in options else "" user_email = options['user_email'] if 'user_email' in options else ""
if user_email: if user_email:
@ -33,12 +31,8 @@ class Command(BaseCommand):
PROJECT_PATH = os.path.abspath(os.path.dirname(__name__)) PROJECT_PATH = os.path.abspath(os.path.dirname(__name__))
if not os.path.exists("%s/outputs" % PROJECT_PATH): if not os.path.exists("%s/outputs" % PROJECT_PATH):
os.mkdir("%s/outputs" % PROJECT_PATH) os.mkdir("%s/outputs" % PROJECT_PATH)
public_templates_plugin = DCLCalculatorPluginModel.objects.filter(cmsplugin_ptr_id=23356).first() for vm_template in VMTemplate.objects.all():
ipv6_templates_plugin = DCLCalculatorPluginModel.objects.filter(cmsplugin_ptr_id=21943).first() vm_name = 'test-%s' % vm_template.name
templates = public_templates_plugin.vm_templates_to_show + ipv6_templates_plugin.vm_templates_to_show
vm_templates = VMTemplate.objects.filter(opennebula_vm_template_id__in=templates)
for vm_template in vm_templates:
vm_name = 'test-%s-%s' % (vm_template.vm_type, vm_template.name)
vm_id = manager.create_vm( vm_id = manager.create_vm(
template_id=vm_template.opennebula_vm_template_id, template_id=vm_template.opennebula_vm_template_id,
specs=specs, specs=specs,
@ -58,7 +52,6 @@ class Command(BaseCommand):
%s %s''' % (vm_name, %s %s''' % (vm_name,
vm_template.opennebula_vm_template_id, vm_template.opennebula_vm_template_id,
vm_template.vm_type) vm_template.vm_type)
error_dict[vm_name] = result_dict[vm_name]
self.stdout.write(self.style.ERROR(result_dict[vm_name])) self.stdout.write(self.style.ERROR(result_dict[vm_name]))
sleep(1) sleep(1)
date_str = datetime.datetime.strftime( date_str = datetime.datetime.strftime(
@ -69,12 +62,4 @@ class Command(BaseCommand):
'w', 'w',
encoding='utf-8') as f: encoding='utf-8') as f:
f.write(json.dumps(result_dict)) f.write(json.dumps(result_dict))
if error_dict:
email_data = {
'subject': 'Check VM Templates ERROR',
'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
'to': [settings.ADMIN_EMAIL],
'body': json.dumps(error_dict),
}
send_plain_email_task.delay(email_data)
self.stdout.write(self.style.SUCCESS("Done")) self.stdout.write(self.style.SUCCESS("Done"))

View file

@ -1,54 +0,0 @@
from django.core.management.base import BaseCommand
from datacenterlight.tasks import handle_metadata_and_emails
from datacenterlight.models import StripePlan
from opennebula_api.models import OpenNebulaManager
from membership.models import CustomUser
from hosting.models import GenericProduct
import logging
import json
import sys
import stripe
logger = logging.getLogger(__name__)
class Command(BaseCommand):
help = '''Stripe plans created before version 3.4 saved the plan name like generic-{subscription_id}-amount. This
command aims at replacing this with the actual product name
'''
def handle(self, *args, **options):
cnt = 0
self.stdout.write(
self.style.SUCCESS(
'In Fix generic stripe plan product names'
)
)
plans_to_change = StripePlan.objects.filter(stripe_plan_id__startswith='generic')
for plan in plans_to_change:
response = input("Press 'y' to continue: ")
# Check if the user entered 'y'
if response.lower() == 'y':
plan_name = plan.stripe_plan_id
first_index_hyphen = plan_name.index("-") + 1
product_id = plan_name[
first_index_hyphen:(plan_name[first_index_hyphen:].index("-")) + first_index_hyphen]
gp = GenericProduct.objects.get(id=product_id)
if gp:
cnt += 1
# update stripe
sp = stripe.Plan.retrieve(plan_name)
pr = stripe.Product.retrieve(sp.product)
pr.name = gp.product_name
pr.save()
# update local
spl = StripePlan.objects.get(stripe_plan_id=plan_name)
spl.stripe_plan_name = gp.product_name
spl.save()
print("%s. %s => %s" % (cnt, plan_name, gp.product_name))
else:
print("Invalid input. Please try again.")
sys.exit()
print("Done")

View file

@ -73,7 +73,6 @@ def get_line_item_from_hosting_order_charge(hosting_order_id):
:return: :return:
""" """
try: try:
print("Hositng order id = %s" % hosting_order_id)
hosting_order = HostingOrder.objects.get(id = hosting_order_id) hosting_order = HostingOrder.objects.get(id = hosting_order_id)
if hosting_order.stripe_charge_id: if hosting_order.stripe_charge_id:
return mark_safe(""" return mark_safe("""
@ -145,7 +144,7 @@ def get_line_item_from_stripe_invoice(invoice):
""".format( """.format(
vm_id=vm_id if vm_id > 0 else "", vm_id=vm_id if vm_id > 0 else "",
ip_addresses=mark_safe(get_ip_addresses(vm_id)) if vm_id > 0 else ip_addresses=mark_safe(get_ip_addresses(vm_id)) if vm_id > 0 else
mark_safe(get_product_name(plan_name)) if plan_name.startswith("generic-") else plan_name, mark_safe(get_product_name(plan_name)),
period=mark_safe("%s — %s" % ( period=mark_safe("%s — %s" % (
datetime.datetime.fromtimestamp(start_date).strftime('%Y-%m-%d'), datetime.datetime.fromtimestamp(start_date).strftime('%Y-%m-%d'),
datetime.datetime.fromtimestamp(end_date).strftime('%Y-%m-%d'))), datetime.datetime.fromtimestamp(end_date).strftime('%Y-%m-%d'))),
@ -161,7 +160,8 @@ def get_product_name(plan_name):
product_name = "" product_name = ""
if plan_name and plan_name.startswith("generic-"): if plan_name and plan_name.startswith("generic-"):
first_index_hyphen = plan_name.index("-") + 1 first_index_hyphen = plan_name.index("-") + 1
product_id = plan_name[first_index_hyphen:(plan_name[first_index_hyphen:].index("-")) + first_index_hyphen] product_id = plan_name[first_index_hyphen:
(plan_name[first_index_hyphen:].index("-")) + first_index_hyphen]
try: try:
product = GenericProduct.objects.get(id=product_id) product = GenericProduct.objects.get(id=product_id)
product_name = product.product_name product_name = product.product_name

View file

@ -42,8 +42,6 @@ from .utils import (
get_cms_integration, create_vm, clear_all_session_vars, validate_vat_number get_cms_integration, create_vm, clear_all_session_vars, validate_vat_number
) )
from datacenterlight.templatetags.custom_tags import get_product_name
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -65,23 +63,23 @@ class ContactUsView(FormView):
) )
def form_valid(self, form): def form_valid(self, form):
#form.save() form.save()
#from_emails = { from_emails = {
# 'glasfaser': 'glasfaser@ungleich.ch' 'glasfaser': 'glasfaser@ungleich.ch'
#} }
#from_page = self.request.POST.get('from_page') from_page = self.request.POST.get('from_page')
#email_data = { email_data = {
# 'subject': "{dcl_text} Message from {sender}".format( 'subject': "{dcl_text} Message from {sender}".format(
# dcl_text=settings.DCL_TEXT, dcl_text=settings.DCL_TEXT,
# sender=form.cleaned_data.get('email') sender=form.cleaned_data.get('email')
# ), ),
# 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
# 'to': [from_emails.get(from_page, 'support@ungleich.ch')], 'to': [from_emails.get(from_page, 'support@ungleich.ch')],
# 'body': "\n".join( 'body': "\n".join(
# ["%s=%s" % (k, v) for (k, v) in form.cleaned_data.items()]), ["%s=%s" % (k, v) for (k, v) in form.cleaned_data.items()]),
# 'reply_to': [form.cleaned_data.get('email')], 'reply_to': [form.cleaned_data.get('email')],
#} }
#send_plain_email_task.delay(email_data) send_plain_email_task.delay(email_data)
if self.request.is_ajax(): if self.request.is_ajax():
return self.render_to_response( return self.render_to_response(
self.get_context_data(success=True, contact_form=form)) self.get_context_data(success=True, contact_form=form))
@ -201,8 +199,6 @@ class IndexView(CreateView):
ssd_size=storage, ssd_size=storage,
pricing_name=vm_pricing_name pricing_name=vm_pricing_name
) )
if request.user.id == 51:
print("User is test")
specs = { specs = {
'cpu': cores, 'cpu': cores,
'memory': memory, 'memory': memory,
@ -590,9 +586,6 @@ class OrderConfirmationView(DetailView, FormView):
context = {} context = {}
# this is amount to be charge/subscribed before VAT and discount # this is amount to be charge/subscribed before VAT and discount
# and expressed in chf. To convert to cents, multiply by 100 # and expressed in chf. To convert to cents, multiply by 100
print("******************************")
print("User = {}, ID = {}".format(request.user, request.user.id))
print("******************************")
amount_to_charge = 0 amount_to_charge = 0
vm_specs = None vm_specs = None
if (('specs' not in request.session or 'user' not in request.session) if (('specs' not in request.session or 'user' not in request.session)
@ -618,7 +611,7 @@ class OrderConfirmationView(DetailView, FormView):
# TODO check when we go through this case (to me, it seems useless) # TODO check when we go through this case (to me, it seems useless)
card_id = self.request.session.get('card_id') card_id = self.request.session.get('card_id')
logger.debug("NO id_payment_method, using card: %s" % card_id) logger.debug("NO id_payment_method, using card: %s" % card_id)
card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) card_detail = UserCardDetail.objects.get(id=card_id)
context['cc_last4'] = card_detail.last4 context['cc_last4'] = card_detail.last4
context['cc_brand'] = card_detail.brand context['cc_brand'] = card_detail.brand
context['cc_exp_year'] = card_detail.exp_year context['cc_exp_year'] = card_detail.exp_year
@ -652,8 +645,6 @@ class OrderConfirmationView(DetailView, FormView):
pricing_name=vm_specs['pricing_name'], pricing_name=vm_specs['pricing_name'],
vat_rate=user_country_vat_rate * 100 vat_rate=user_country_vat_rate * 100
) )
if request.user.id == 51:
print("User is test")
vm_specs["price"] = price vm_specs["price"] = price
vm_specs["price_after_discount"] = price - discount["amount"] vm_specs["price_after_discount"] = price - discount["amount"]
amount_to_charge = price amount_to_charge = price
@ -859,7 +850,7 @@ class OrderConfirmationView(DetailView, FormView):
return show_error(msg, self.request) return show_error(msg, self.request)
elif 'card_id' in request.session: elif 'card_id' in request.session:
card_id = request.session.get('card_id') card_id = request.session.get('card_id')
user_card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) user_card_detail = UserCardDetail.objects.get(id=card_id)
card_details_dict = { card_details_dict = {
'last4': user_card_detail.last4, 'last4': user_card_detail.last4,
'brand': user_card_detail.brand, 'brand': user_card_detail.brand,
@ -909,21 +900,15 @@ class OrderConfirmationView(DetailView, FormView):
2 2
) )
) )
stripe_plan_id = "generic-{0}-{1:.2f}".format( plan_name = "generic-{0}-{1:.2f}".format(
request.session['generic_payment_details']['product_id'], request.session['generic_payment_details']['product_id'],
amount_to_be_charged amount_to_be_charged
) )
try: stripe_plan_id = plan_name
product = GenericProduct.objects.get(id=request.session['generic_payment_details']['product_id'])
plan_name = product.product_name
except Exception as ex:
logger.debug("Errori {}" % str(ex))
plan_name = get_product_name(stripe_plan_id)
recurring_interval = request.session['generic_payment_details']['recurring_interval'] recurring_interval = request.session['generic_payment_details']['recurring_interval']
if recurring_interval == "year": if recurring_interval == "year":
stripe_plan_id = "{}-yearly".format(stripe_plan_id) plan_name = "{}-yearly".format(plan_name)
plan_name = "{} (yearly)".format(plan_name) stripe_plan_id = plan_name
logger.debug("Plan name = {}, Stripe Plan id = {}".format(plan_name, stripe_plan_id))
else: else:
template = request.session.get('template') template = request.session.get('template')
specs = request.session.get('specs') specs = request.session.get('specs')
@ -1016,8 +1001,6 @@ class OrderConfirmationView(DetailView, FormView):
# due to some reason. So, we would want to dissociate this card # due to some reason. So, we would want to dissociate this card
# here. # here.
# ... # ...
logger.debug("In 1 ***")
logger.debug("stripe_subscription_obj == %s" % stripe_subscription_obj)
msg = subscription_result.get('error') msg = subscription_result.get('error')
return show_error(msg, self.request) return show_error(msg, self.request)
elif stripe_subscription_obj.status == 'incomplete': elif stripe_subscription_obj.status == 'incomplete':
@ -1211,10 +1194,9 @@ def get_or_create_custom_user(request, stripe_api_cus_id):
def set_user_card(card_id, stripe_api_cus_id, custom_user, def set_user_card(card_id, stripe_api_cus_id, custom_user,
card_details_response): card_details_response):
logger.debug(":: set_user_card")
if card_id: if card_id:
logger.debug("card_id %s was in request" % card_id) logger.debug("card_id %s was in request" % card_id)
user_card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) user_card_detail = UserCardDetail.objects.get(id=card_id)
card_details_dict = { card_details_dict = {
'last4': user_card_detail.last4, 'last4': user_card_detail.last4,
'brand': user_card_detail.brand, 'brand': user_card_detail.brand,
@ -1226,24 +1208,21 @@ def set_user_card(card_id, stripe_api_cus_id, custom_user,
stripe_source_id=user_card_detail.card_id stripe_source_id=user_card_detail.card_id
) )
else: else:
logger.debug(" card_id was NOT in request, using " logger.debug("card_id was NOT in request, using "
"card_details_response") "card_details_response")
ucd = UserCardDetail.get_or_create_user_card_detail( ucd = UserCardDetail.get_or_create_user_card_detail(
stripe_customer=custom_user.stripecustomer, stripe_customer=custom_user.stripecustomer,
card_details=card_details_response card_details=card_details_response
) )
logger.debug(" ucd = %s" % ucd)
UserCardDetail.save_default_card_local( UserCardDetail.save_default_card_local(
custom_user.stripecustomer.stripe_id, custom_user.stripecustomer.stripe_id,
ucd.card_id ucd.card_id
) )
logger.debug(" after save_default_card_local")
card_details_dict = { card_details_dict = {
'last4': ucd.last4, 'last4': ucd.last4,
'brand': ucd.brand, 'brand': ucd.brand,
'card_id': ucd.card_id 'card_id': ucd.card_id
} }
logger.debug("card_detail_dict = %s" % card_details_dict)
return card_details_dict return card_details_dict
@ -1437,30 +1416,6 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response,
""" """
logger.debug("do_provisioning") logger.debug("do_provisioning")
try:
params = {
'request': request,
'stripe_api_cus_id': stripe_api_cus_id,
'card_details_response': card_details_response,
'stripe_subscription_obj': stripe_subscription_obj,
'stripe_onetime_charge': stripe_onetime_charge,
'gp_details': gp_details,
'specs': specs,
'vm_template_id': vm_template_id,
'template': template,
'billing_address_data': billing_address_data,
'real_request': real_request
}
print("Input Parameters:")
for key, value in params.items():
try:
print("{}: {}".format(key, value))
except Exception as e:
print("{}: [Error printing value: {}]".format(key, str(e)))
except Exception as e:
print("Error printing parameters: {}".format(str(e)))
user = request.get('user', None) user = request.get('user', None)
# Create user if the user is not logged in and if he is not already # Create user if the user is not logged in and if he is not already
@ -1472,7 +1427,6 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response,
card_details_dict = set_user_card(card_id, stripe_api_cus_id, custom_user, card_details_dict = set_user_card(card_id, stripe_api_cus_id, custom_user,
card_details_response) card_details_response)
logger.debug("after set_user_card %s" % card_details_dict)
# Save billing address # Save billing address
billing_address_data.update({ billing_address_data.update({
@ -1495,7 +1449,6 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response,
vat_number=billing_address_data['vat_number'] vat_number=billing_address_data['vat_number']
) )
billing_address.save() billing_address.save()
logger.debug("billing_address saved")
order = HostingOrder.create( order = HostingOrder.create(
price=request['generic_payment_details']['amount'], price=request['generic_payment_details']['amount'],
@ -1503,7 +1456,6 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response,
billing_address=billing_address, billing_address=billing_address,
vm_pricing=VMPricing.get_default_pricing() vm_pricing=VMPricing.get_default_pricing()
) )
logger.debug("hosting order created")
# Create a Hosting Bill # Create a Hosting Bill
HostingBill.create(customer=stripe_cus, HostingBill.create(customer=stripe_cus,
@ -1560,9 +1512,7 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response,
["%s=%s" % (k, v) for (k, v) in context.items()]), ["%s=%s" % (k, v) for (k, v) in context.items()]),
'reply_to': [context['email']], 'reply_to': [context['email']],
} }
logger.debug("Sending email")
send_plain_email_task.delay(email_data) send_plain_email_task.delay(email_data)
logger.debug("After Sending email")
recurring_text = _(" This is a monthly recurring plan.") recurring_text = _(" This is a monthly recurring plan.")
if gp_details['recurring_interval'] == "year": if gp_details['recurring_interval'] == "year":
recurring_text = _(" This is an yearly recurring plan.") recurring_text = _(" This is an yearly recurring plan.")
@ -1586,7 +1536,6 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response,
), ),
'reply_to': ['info@ungleich.ch'], 'reply_to': ['info@ungleich.ch'],
} }
logger.debug("Before Sending customer email")
send_plain_email_task.delay(email_data) send_plain_email_task.delay(email_data)
redirect_url = reverse('datacenterlight:index') redirect_url = reverse('datacenterlight:index')
logger.debug("Sent user/admin emails") logger.debug("Sent user/admin emails")
@ -1630,7 +1579,7 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response,
def get_error_response_dict(msg, request): def get_error_response_dict(msg, request):
logger.debug("Init get_error_response_dict {}".format(msg)) logger.error(msg)
response = { response = {
'status': False, 'status': False,
'redirect': "{url}#{section}".format( 'redirect': "{url}#{section}".format(

View file

@ -777,9 +777,3 @@ if DEBUG:
from .local import * # flake8: noqa from .local import * # flake8: noqa
else: else:
from .prod import * # flake8: noqa from .prod import * # flake8: noqa
# Try to load dynamic configuration, if it exists
try:
from .dynamic import * # flake8: noqa
except ImportError:
pass

View file

@ -1,19 +0,0 @@
#!/bin/sh
set -uex
cd /usr/src/app/
cat > dynamicweb/settings/dynamic.py <<EOF
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': '${POSTGRES_DB}',
'USER': '${POSTGRES_USER}',
'PASSWORD': '${POSTGRES_PASSWORD}',
'HOST': '${POSTGRES_HOST}',
'PORT': '5432',
}
}
EOF
exec "$@"

View file

@ -1,144 +0,0 @@
from django.core.management.base import BaseCommand
import datetime
import csv
import logging
import stripe
from hosting.models import VATRates
from utils.hosting_utils import get_vat_rate_for_country
from django.conf import settings
from membership.models import CustomUser, StripeCustomer
stripe.api_key = settings.STRIPE_API_PRIVATE_KEY
logger = logging.getLogger(__name__)
class Command(BaseCommand):
help = '''CH vat rate changes on 2024-01-01 from 7.7% to 8.1%. This commands makes the necessary changes'''
def handle(self, *args, **options):
MAKE_MODIFS=False
try:
country_to_change = 'CH'
currency_to_change = 'CHF'
new_rate = 0.081
user_country_vat_rate = get_vat_rate_for_country(country_to_change)
logger.debug("Existing VATRate for %s %s " % (country_to_change, user_country_vat_rate))
vat_rate = VATRates.objects.get(
territory_codes=country_to_change, start_date__isnull=False, stop_date=None
)
logger.debug("VAT rate for %s is %s" % (country_to_change, vat_rate.rate))
logger.debug("vat_rate object = %s" % vat_rate)
logger.debug("Create end date for the VATRate %s" % vat_rate.id)
# if MAKE_MODIFS:
# vat_rate.stop_date = datetime.date(2023, 12, 31)
# vat_rate.save()
# print("Creating a new VATRate for CH")
# obj, created = VATRates.objects.get_or_create(
# start_date=datetime.date(2024, 1, 1),
# stop_date=None,
# territory_codes=country_to_change,
# currency_code=currency_to_change,
# rate=new_rate,
# rate_type="standard",
# description="Switzerland standard VAT (added manually on %s)" % datetime.datetime.now()
# )
# if created:
# logger.debug("Created new VAT Rate for %s with the new rate %s" % (country_to_change, new_rate))
# logger.debug(obj)
# else:
# logger.debug("VAT Rate for %s already exists with the rate %s" % (country_to_change, new_rate))
#
logger.debug("Getting all subscriptions of %s that need a VAT Rate change")
subscriptions = stripe.Subscription.list(limit=100) # Increase the limit to 100 per page (maximum)
ch_subs = []
while subscriptions:
for subscription in subscriptions:
if len(subscription.default_tax_rates) > 0 and subscription.default_tax_rates[0].jurisdiction and subscription.default_tax_rates[0].jurisdiction.lower() == 'ch':
ch_subs.append(subscription)
elif len(subscription.default_tax_rates) > 0:
print("subscription %s belongs to %s" % (subscription.id, subscription.default_tax_rates[0].jurisdiction))
else:
print("subscription %s does not have a tax rate" % subscription.id)
if subscriptions.has_more:
print("FETCHING MORE")
subscriptions = stripe.Subscription.list(limit=100, starting_after=subscriptions.data[-1])
else:
break
logger.debug("There are %s ch subscription that need VAT rate update" % len(ch_subs))
# CSV column headers
csv_headers = [
"customer_name",
"customer_email",
"stripe_customer_id",
"subscription_id",
"subscription_name",
"amount",
"vat_rate"
]
# CSV file name
csv_filename = "ch_subscriptions_change_2024.csv"
# Write subscription data to CSV file
with open(csv_filename, mode='w', newline='') as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=csv_headers)
writer.writeheader()
for subscription in ch_subs:
subscription_id = subscription["id"]
stripe_customer_id = subscription.get("customer", "")
vat_rate = subscription.get("tax_percent", "")
c_user = CustomUser.objects.get(
id=StripeCustomer.objects.filter(stripe_id=stripe_customer_id)[0].user.id)
if c_user:
customer_name = c_user.name.encode('utf-8')
customer_email = c_user.email
items = subscription.get("items", {}).get("data", [])
for item in items:
subscription_name = item.get("plan", {}).get("id", "")
amount = item.get("plan", {}).get("amount", "")
# Convert amount to a proper format (e.g., cents to dollars)
amount_in_chf = amount / 100 # Adjust this conversion as needed
# Writing to CSV
writer.writerow({
"customer_name": customer_name,
"customer_email": customer_email,
"stripe_customer_id": stripe_customer_id,
"subscription_id": subscription_id,
"subscription_name": subscription_name,
"amount": amount_in_chf,
"vat_rate": vat_rate # Fill in VAT rate if available
})
else:
print("No customuser for %s %s" % (stripe_customer_id, subscription_id))
if MAKE_MODIFS:
print("Making modifications now")
tax_rate_obj = stripe.TaxRate.create(
display_name="VAT",
description="VAT for %s" % country_to_change,
jurisdiction=country_to_change,
percentage=new_rate,
inclusive=False,
)
stripe_tax_rate = StripeTaxRate.objects.create(
display_name=tax_rate_obj.display_name,
description=tax_rate_obj.description,
jurisdiction=tax_rate_obj.jurisdiction,
percentage=tax_rate_obj.percentage,
inclusive=False,
tax_rate_id=tax_rate_obj.id
)
for ch_sub in ch_subs:
ch_sub.default_tax_rates = [stripe_tax_rate.tax_rate_id]
ch_sub.save()
logger.debug("Default tax rate updated for %s" % ch_sub.id)
else:
print("Not making any modifications because MAKE_MODIFS=False")
except Exception as e:
print(" *** Error occurred. Details {}".format(str(e)))

View file

@ -1,143 +0,0 @@
from django.core.management.base import BaseCommand
import datetime
import csv
import logging
import stripe
from hosting.models import VATRates, StripeTaxRate
from utils.hosting_utils import get_vat_rate_for_country
from django.conf import settings
from membership.models import CustomUser, StripeCustomer
stripe.api_key = settings.STRIPE_API_PRIVATE_KEY
logger = logging.getLogger(__name__)
class Command(BaseCommand):
help = '''FI vat rate changes on 2024-09-01 from 24% to 25.5%. This commands makes the necessary changes'''
def handle(self, *args, **options):
MAKE_MODIFS=False
try:
country_to_change = 'FI'
currency_to_change = 'EUR'
new_rate = 25.5
user_country_vat_rate = get_vat_rate_for_country(country_to_change)
logger.debug("Existing VATRate for %s %s " % (country_to_change, user_country_vat_rate))
vat_rate = VATRates.objects.get(
territory_codes=country_to_change, start_date__isnull=False, stop_date=None
)
logger.debug("VAT rate for %s is %s" % (country_to_change, vat_rate.rate))
logger.debug("vat_rate object = %s" % vat_rate)
logger.debug("Create end date for the VATRate %s" % vat_rate.id)
#if MAKE_MODIFS:
# vat_rate.stop_date = datetime.date(2024, 8, 31)
# vat_rate.save()
# print("Creating a new VATRate for FI")
# obj, created = VATRates.objects.get_or_create(
# start_date=datetime.date(2024, 9, 1),
# stop_date=None,
# territory_codes=country_to_change,
# currency_code=currency_to_change,
# rate=new_rate * 0.01,
# rate_type="standard",
# description="FINLAND standard VAT (added manually on %s)" % datetime.datetime.now()
# )
# if created:
# logger.debug("Created new VAT Rate for %s with the new rate %s" % (country_to_change, new_rate))
# logger.debug(obj)
# else:
# logger.debug("VAT Rate for %s already exists with the rate %s" % (country_to_change, new_rate))
logger.debug("Getting all subscriptions of %s that need a VAT Rate change")
subscriptions = stripe.Subscription.list(limit=100) # Increase the limit to 100 per page (maximum)
fi_subs = []
while subscriptions:
for subscription in subscriptions:
if len(subscription.default_tax_rates) > 0 and subscription.default_tax_rates[0].jurisdiction and subscription.default_tax_rates[0].jurisdiction.lower() == 'fi':
fi_subs.append(subscription)
elif len(subscription.default_tax_rates) > 0:
print("subscription %s belongs to %s" % (subscription.id, subscription.default_tax_rates[0].jurisdiction))
else:
print("subscription %s does not have a tax rate" % subscription.id)
if subscriptions.has_more:
print("FETCHING MORE")
subscriptions = stripe.Subscription.list(limit=100, starting_after=subscriptions.data[-1])
else:
break
logger.debug("There are %s FI subscription that need VAT rate update" % len(fi_subs))
# CSV column headers
csv_headers = [
"customer_name",
"customer_email",
"stripe_customer_id",
"subscription_id",
"subscription_name",
"amount",
"vat_rate"
]
# CSV file name
csv_filename = "fi_subscriptions_change_2024.csv"
# Write subscription data to CSV file
with open(csv_filename, mode='w', newline='') as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=csv_headers)
writer.writeheader()
for subscription in fi_subs:
subscription_id = subscription["id"]
stripe_customer_id = subscription.get("customer", "")
vat_rate = subscription.get("tax_percent", "")
c_user = CustomUser.objects.get(
id=StripeCustomer.objects.filter(stripe_id=stripe_customer_id)[0].user.id)
if c_user:
customer_name = c_user.name.encode('utf-8')
customer_email = c_user.email
items = subscription.get("items", {}).get("data", [])
for item in items:
subscription_name = item.get("plan", {}).get("id", "")
amount = item.get("plan", {}).get("amount", "")
# Convert amount to a proper format (e.g., cents to dollars)
amount_in_chf = amount / 100 # Adjust this conversion as needed
# Writing to CSV
writer.writerow({
"customer_name": customer_name,
"customer_email": customer_email,
"stripe_customer_id": stripe_customer_id,
"subscription_id": subscription_id,
"subscription_name": subscription_name,
"amount": amount_in_chf,
"vat_rate": vat_rate # Fill in VAT rate if available
})
else:
print("No customuser for %s %s" % (stripe_customer_id, subscription_id))
if MAKE_MODIFS:
print("Making modifications now")
tax_rate_obj = stripe.TaxRate.create(
display_name="VAT",
description="VAT for %s" % country_to_change,
jurisdiction=country_to_change,
percentage=new_rate,
inclusive=False,
)
stripe_tax_rate = StripeTaxRate.objects.create(
display_name=tax_rate_obj.display_name,
description=tax_rate_obj.description,
jurisdiction=tax_rate_obj.jurisdiction,
percentage=tax_rate_obj.percentage,
inclusive=False,
tax_rate_id=tax_rate_obj.id
)
for fi_sub in fi_subs:
fi_sub.default_tax_rates = [stripe_tax_rate.tax_rate_id]
fi_sub.save()
logger.debug("Default tax rate updated for %s" % fi_sub.id)
else:
print("Not making any modifications because MAKE_MODIFS=False")
except Exception as e:
print(" *** Error occurred. Details {}".format(str(e)))

View file

@ -699,116 +699,15 @@ class UserCardDetail(AssignPermissionsMixin, models.Model):
@staticmethod @staticmethod
def save_default_card_local(stripe_api_cus_id, card_id): def save_default_card_local(stripe_api_cus_id, card_id):
print("save_default_card_local {}, {}".format(stripe_api_cus_id, card_id))
stripe_cust = StripeCustomer.objects.get(stripe_id=stripe_api_cus_id) stripe_cust = StripeCustomer.objects.get(stripe_id=stripe_api_cus_id)
print(" stripe_cust={}".format(stripe_cust)) user_card_detail = UserCardDetail.objects.get(
user_card_detail = UserCardDetail.get_ucd_from_stripe_cust_n_card_id( stripe_customer=stripe_cust, card_id=card_id
stripe_cust, card_id
) )
print(" user_card_detail={}".format(user_card_detail.__dict__))
for card in stripe_cust.usercarddetail_set.all(): for card in stripe_cust.usercarddetail_set.all():
card.preferred = False card.preferred = False
card.save() card.save()
user_card_detail.preferred = True user_card_detail.preferred = True
user_card_detail.save() user_card_detail.save()
print(" save_default_card_local DONE")
@staticmethod
def get_ucd_from_card_id(card_id):
try:
user_card_details = UserCardDetail.objects.filter(
card_id=card_id
).order_by('-id')
if user_card_details.count() > 1:
# Log a warning about the duplicate entries
logger.warning(
"Multiple UserCardDetail objects found for card_id={}. "
"Found {} objects. Using the latest one.".format(
card_id, user_card_details.count()
)
)
# Use the first object found
user_card_detail = user_card_details.first()
elif user_card_details.count() == 1:
# Exactly one object found, proceed as intended
user_card_detail = user_card_details.first()
else:
# No object found for the given customer and card_id.
# Depending on expected behavior, you might want to raise an error or handle this case.
# If the original get() call happened here, it would raise DoesNotExist.
logger.error(
"No UserCardDetail found for card_id={}.".format(card_id)
)
raise UserCardDetail.DoesNotExist("No UserCardDetail found for card {}".format(card_id))
if user_card_details.count() > 1:
# Log a warning about the duplicate entries
logger.warning(
"Multiple UserCardDetail objects found for card_id={}. "
"Found {} objects. Using the first one.".format(
card_id, user_card_details.count()
)
)
# Use the first object found
user_card_detail = user_card_details.first()
elif user_card_details.count() == 1:
# Exactly one object found, proceed as intended
user_card_detail = user_card_details.first()
else:
# No object found for the given customer and card_id.
# Depending on expected behavior, you might want to raise an error or handle this case.
# If the original get() call happened here, it would raise DoesNotExist.
logger.error(
"No UserCardDetail found for card_id={}.".format(card_id)
)
raise UserCardDetail.DoesNotExist("No UserCardDetail found for card {}".format(card_id))
except Exception as e:
# Catch other potential exceptions during the filter/get process if necessary
logger.error("An unexpected error occurred while fetching UserCardDetail: {}".format(e))
raise
return user_card_detail
@staticmethod
def get_ucd_from_stripe_cust_n_card_id(stripe_cust, card_id):
try:
user_card_details = UserCardDetail.objects.filter(
stripe_customer=stripe_cust, card_id=card_id
).order_by('-id')
if user_card_details.count() > 1:
# Log a warning about the duplicate entries
logger.warning(
"Multiple UserCardDetail objects found for stripe_customer_id={} and card_id={}. "
"Found {} objects. Using the first one.".format(
stripe_cust.id, card_id, user_card_details.count()
)
)
# Use the first object found
user_card_detail = user_card_details.first()
elif user_card_details.count() == 1:
# Exactly one object found, proceed as intended
user_card_detail = user_card_details.first()
else:
# No object found for the given customer and card_id.
# Depending on expected behavior, you might want to raise an error or handle this case.
# If the original get() call happened here, it would raise DoesNotExist.
logger.error(
"No UserCardDetail found for stripe_customer_id={} and card_id={}.".format(
stripe_cust.id, card_id
)
)
raise UserCardDetail.DoesNotExist(
"No UserCardDetail found for customer {}, card {}".format(
stripe_cust.id, card_id
)
)
except Exception as e:
# Catch other potential exceptions during the filter/get process if necessary
logger.error("An unexpected error occurred while fetching UserCardDetail: {}".format(e))
raise
return user_card_detail
@staticmethod @staticmethod
def get_user_card_details(stripe_customer, card_details): def get_user_card_details(stripe_customer, card_details):

View file

@ -46,7 +46,7 @@
<div class="vm-vmid"> <div class="vm-vmid">
<div class="vm-item-subtitle">{% trans "Current Pricing" %}</div> <div class="vm-item-subtitle">{% trans "Current Pricing" %}</div>
<div class="vm-item-lg">{{order.price|floatformat:2|intcomma}} CHF/{% if order.generic_product %}{% trans order.generic_product.product_subscription_interval %}{% else %}{% trans "Month" %}{% endif %}</div> <div class="vm-item-lg">{{order.price|floatformat:2|intcomma}} CHF/{% if order.generic_product %}{% trans order.generic_product.product_subscription_interval %}{% else %}{% trans "Month" %}{% endif %}</div>
{% if inv_url %}<a class="btn btn-vm-invoice" href="{{inv_url}}" target="_blank">{% trans "See Invoice" %}</a>{%else%}{% trans "No invoice as of now" %}{% endif %} <a class="btn btn-vm-invoice" href="{{inv_url}}" target="_blank">{% trans "See Invoice" %}</a>
</div> </div>
</div> </div>
<div class="vm-detail-item"> <div class="vm-detail-item">

View file

@ -554,23 +554,14 @@ class SettingsView(LoginRequiredMixin, FormView):
Check if the user already saved contact details. If so, then show Check if the user already saved contact details. If so, then show
the form populated with those details, to let user change them. the form populated with those details, to let user change them.
""" """
username = self.request.GET.get('username')
if self.request.user.is_admin and username:
user = CustomUser.objects.get(username=username)
else:
user = self.request.user
return form_class( return form_class(
instance=user.billing_addresses.first(), instance=self.request.user.billing_addresses.first(),
**self.get_form_kwargs()) **self.get_form_kwargs())
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(SettingsView, self).get_context_data(**kwargs) context = super(SettingsView, self).get_context_data(**kwargs)
# Get user # Get user
username = self.request.GET.get('username') user = self.request.user
if self.request.user.is_admin and username:
user = CustomUser.objects.get(username=username)
else:
user = self.request.user
stripe_customer = None stripe_customer = None
if hasattr(user, 'stripecustomer'): if hasattr(user, 'stripecustomer'):
stripe_customer = user.stripecustomer stripe_customer = user.stripecustomer
@ -810,7 +801,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
card_id = form.cleaned_data.get('card') card_id = form.cleaned_data.get('card')
customer = owner.stripecustomer customer = owner.stripecustomer
try: try:
user_card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) user_card_detail = UserCardDetail.objects.get(id=card_id)
if not request.user.has_perm( if not request.user.has_perm(
'view_usercarddetail', user_card_detail 'view_usercarddetail', user_card_detail
): ):
@ -1014,7 +1005,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView, FormView):
context['cc_exp_month'] = card_details_response['exp_month'] context['cc_exp_month'] = card_details_response['exp_month']
else: else:
card_id = self.request.session.get('card_id') card_id = self.request.session.get('card_id')
card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) card_detail = UserCardDetail.objects.get(id=card_id)
context['cc_last4'] = card_detail.last4 context['cc_last4'] = card_detail.last4
context['cc_brand'] = card_detail.brand context['cc_brand'] = card_detail.brand
context['cc_exp_year'] = card_detail.exp_year context['cc_exp_year'] = card_detail.exp_year
@ -1128,7 +1119,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView, FormView):
return JsonResponse(response) return JsonResponse(response)
else: else:
card_id = request.session.get('card_id') card_id = request.session.get('card_id')
user_card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) user_card_detail = UserCardDetail.objects.get(id=card_id)
card_details_dict = { card_details_dict = {
'last4': user_card_detail.last4, 'last4': user_card_detail.last4,
'brand': user_card_detail.brand, 'brand': user_card_detail.brand,
@ -1339,7 +1330,7 @@ class InvoiceListView(LoginRequiredMixin, TemplateView):
).order_by('-created_at') ).order_by('-created_at')
stripe_chgs = [] stripe_chgs = []
for ho in hosting_orders: for ho in hosting_orders:
stripe_chgs.append({ho: stripe.Charge.retrieve(ho.stripe_charge_id)}) stripe_chgs.append({ho.id: stripe.Charge.retrieve(ho.stripe_charge_id)})
paginator_charges = Paginator(stripe_chgs, 10) paginator_charges = Paginator(stripe_chgs, 10)
try: try:
@ -1544,12 +1535,7 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView):
ordering = '-id' ordering = '-id'
def get_queryset(self): def get_queryset(self):
username = self.request.GET.get('username') owner = self.request.user
if self.request.user.is_admin and username:
user = CustomUser.objects.get(username=username)
else:
user = self.request.user
owner = user
manager = OpenNebulaManager(email=owner.username, manager = OpenNebulaManager(email=owner.username,
password=owner.password) password=owner.password)
try: try:
@ -1708,11 +1694,7 @@ class VirtualMachineView(LoginRequiredMixin, View):
login_url = reverse_lazy('hosting:login') login_url = reverse_lazy('hosting:login')
def get_object(self): def get_object(self):
username = self.request.GET.get('username') owner = self.request.user
if self.request.user.is_admin and username:
owner = CustomUser.objects.get(username=username)
else:
owner = self.request.user
vm = None vm = None
manager = OpenNebulaManager( manager = OpenNebulaManager(
email=owner.username, email=owner.username,
@ -1768,10 +1750,7 @@ class VirtualMachineView(LoginRequiredMixin, View):
subscription=hosting_order.subscription_id, subscription=hosting_order.subscription_id,
count=1 count=1
) )
if stripe_obj.data: inv_url = stripe_obj.data[0].hosted_invoice_url
inv_url = stripe_obj.data[0].hosted_invoice_url
else:
inv_url = ''
elif hosting_order.stripe_charge_id: elif hosting_order.stripe_charge_id:
stripe_obj = stripe.Charge.retrieve( stripe_obj = stripe.Charge.retrieve(
hosting_order.stripe_charge_id hosting_order.stripe_charge_id

View file

@ -25,7 +25,7 @@ django-compressor==2.0
django-debug-toolbar==1.4 django-debug-toolbar==1.4
python-dotenv==0.10.3 python-dotenv==0.10.3
django-extensions==1.6.7 django-extensions==1.6.7
django-filer==1.2.0 django-filer==2.1.2
django-filter==0.13.0 django-filter==0.13.0
django-formtools==1.0 django-formtools==1.0
django-guardian==1.4.4 django-guardian==1.4.4

View file

@ -1,8 +1,7 @@
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.db import models from django.db import models
# Old: http://xml.coverpages.org/country3166.html # http://xml.coverpages.org/country3166.html
# 2023-12-29: Updated list of countries from https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
COUNTRIES = ( COUNTRIES = (
('AD', _('Andorra')), ('AD', _('Andorra')),
('AE', _('United Arab Emirates')), ('AE', _('United Arab Emirates')),
@ -11,6 +10,7 @@ COUNTRIES = (
('AI', _('Anguilla')), ('AI', _('Anguilla')),
('AL', _('Albania')), ('AL', _('Albania')),
('AM', _('Armenia')), ('AM', _('Armenia')),
('AN', _('Netherlands Antilles')),
('AO', _('Angola')), ('AO', _('Angola')),
('AQ', _('Antarctica')), ('AQ', _('Antarctica')),
('AR', _('Argentina')), ('AR', _('Argentina')),
@ -18,7 +18,6 @@ COUNTRIES = (
('AT', _('Austria')), ('AT', _('Austria')),
('AU', _('Australia')), ('AU', _('Australia')),
('AW', _('Aruba')), ('AW', _('Aruba')),
('AX', _('Aland Islands')),
('AZ', _('Azerbaijan')), ('AZ', _('Azerbaijan')),
('BA', _('Bosnia and Herzegovina')), ('BA', _('Bosnia and Herzegovina')),
('BB', _('Barbados')), ('BB', _('Barbados')),
@ -29,13 +28,11 @@ COUNTRIES = (
('BH', _('Bahrain')), ('BH', _('Bahrain')),
('BI', _('Burundi')), ('BI', _('Burundi')),
('BJ', _('Benin')), ('BJ', _('Benin')),
('BL', _('St. Barts')),
('BM', _('Bermuda')), ('BM', _('Bermuda')),
('BN', _('Brunei')), ('BN', _('Brunei Darussalam')),
('BO', _('Bolivia')), ('BO', _('Bolivia')),
('BQ', _('Caribbean Netherlands')),
('BR', _('Brazil')), ('BR', _('Brazil')),
('BS', _('Bahamas')), ('BS', _('Bahama')),
('BT', _('Bhutan')), ('BT', _('Bhutan')),
('BV', _('Bouvet Island')), ('BV', _('Bouvet Island')),
('BW', _('Botswana')), ('BW', _('Botswana')),
@ -43,12 +40,11 @@ COUNTRIES = (
('BZ', _('Belize')), ('BZ', _('Belize')),
('CA', _('Canada')), ('CA', _('Canada')),
('CC', _('Cocos (Keeling) Islands')), ('CC', _('Cocos (Keeling) Islands')),
('CD', _('Congo - Kinshasa')),
('CF', _('Central African Republic')), ('CF', _('Central African Republic')),
('CG', _('Congo - Brazzaville')), ('CG', _('Congo')),
('CH', _('Switzerland')), ('CH', _('Switzerland')),
('CI', _('Ivory Coast')), ('CI', _('Ivory Coast')),
('CK', _('Cook Islands')), ('CK', _('Cook Iislands')),
('CL', _('Chile')), ('CL', _('Chile')),
('CM', _('Cameroon')), ('CM', _('Cameroon')),
('CN', _('China')), ('CN', _('China')),
@ -56,10 +52,9 @@ COUNTRIES = (
('CR', _('Costa Rica')), ('CR', _('Costa Rica')),
('CU', _('Cuba')), ('CU', _('Cuba')),
('CV', _('Cape Verde')), ('CV', _('Cape Verde')),
('CW', _('Curacao')),
('CX', _('Christmas Island')), ('CX', _('Christmas Island')),
('CY', _('Cyprus')), ('CY', _('Cyprus')),
('CZ', _('Czechia')), ('CZ', _('Czech Republic')),
('DE', _('Germany')), ('DE', _('Germany')),
('DJ', _('Djibouti')), ('DJ', _('Djibouti')),
('DK', _('Denmark')), ('DK', _('Denmark')),
@ -75,16 +70,16 @@ COUNTRIES = (
('ET', _('Ethiopia')), ('ET', _('Ethiopia')),
('FI', _('Finland')), ('FI', _('Finland')),
('FJ', _('Fiji')), ('FJ', _('Fiji')),
('FK', _('Falkland Islands')), ('FK', _('Falkland Islands (Malvinas)')),
('FM', _('Micronesia')), ('FM', _('Micronesia')),
('FO', _('Faroe Islands')), ('FO', _('Faroe Islands')),
('FR', _('France')), ('FR', _('France')),
('FX', _('France, Metropolitan')),
('GA', _('Gabon')), ('GA', _('Gabon')),
('GB', _('United Kingdom')), ('GB', _('United Kingdom (Great Britain)')),
('GD', _('Grenada')), ('GD', _('Grenada')),
('GE', _('Georgia')), ('GE', _('Georgia')),
('GF', _('French Guiana')), ('GF', _('French Guiana')),
('GG', _('Guernsey')),
('GH', _('Ghana')), ('GH', _('Ghana')),
('GI', _('Gibraltar')), ('GI', _('Gibraltar')),
('GL', _('Greenland')), ('GL', _('Greenland')),
@ -98,7 +93,7 @@ COUNTRIES = (
('GU', _('Guam')), ('GU', _('Guam')),
('GW', _('Guinea-Bissau')), ('GW', _('Guinea-Bissau')),
('GY', _('Guyana')), ('GY', _('Guyana')),
('HK', _('Hong Kong SAR China')), ('HK', _('Hong Kong')),
('HM', _('Heard & McDonald Islands')), ('HM', _('Heard & McDonald Islands')),
('HN', _('Honduras')), ('HN', _('Honduras')),
('HR', _('Croatia')), ('HR', _('Croatia')),
@ -107,14 +102,12 @@ COUNTRIES = (
('ID', _('Indonesia')), ('ID', _('Indonesia')),
('IE', _('Ireland')), ('IE', _('Ireland')),
('IL', _('Israel')), ('IL', _('Israel')),
('IM', _('Isle of Man')),
('IN', _('India')), ('IN', _('India')),
('IO', _('British Indian Ocean Territory')), ('IO', _('British Indian Ocean Territory')),
('IQ', _('Iraq')), ('IQ', _('Iraq')),
('IR', _('Iran')), ('IR', _('Islamic Republic of Iran')),
('IS', _('Iceland')), ('IS', _('Iceland')),
('IT', _('Italy')), ('IT', _('Italy')),
('JE', _('Jersey')),
('JM', _('Jamaica')), ('JM', _('Jamaica')),
('JO', _('Jordan')), ('JO', _('Jordan')),
('JP', _('Japan')), ('JP', _('Japan')),
@ -124,14 +117,14 @@ COUNTRIES = (
('KI', _('Kiribati')), ('KI', _('Kiribati')),
('KM', _('Comoros')), ('KM', _('Comoros')),
('KN', _('St. Kitts and Nevis')), ('KN', _('St. Kitts and Nevis')),
('KP', _('North Korea')), ('KP', _('Korea, Democratic People\'s Republic of')),
('KR', _('South Korea')), ('KR', _('Korea, Republic of')),
('KW', _('Kuwait')), ('KW', _('Kuwait')),
('KY', _('Cayman Islands')), ('KY', _('Cayman Islands')),
('KZ', _('Kazakhstan')), ('KZ', _('Kazakhstan')),
('LA', _('Laos')), ('LA', _('Lao People\'s Democratic Republic')),
('LB', _('Lebanon')), ('LB', _('Lebanon')),
('LC', _('St. Lucia')), ('LC', _('Saint Lucia')),
('LI', _('Liechtenstein')), ('LI', _('Liechtenstein')),
('LK', _('Sri Lanka')), ('LK', _('Sri Lanka')),
('LR', _('Liberia')), ('LR', _('Liberia')),
@ -139,23 +132,20 @@ COUNTRIES = (
('LT', _('Lithuania')), ('LT', _('Lithuania')),
('LU', _('Luxembourg')), ('LU', _('Luxembourg')),
('LV', _('Latvia')), ('LV', _('Latvia')),
('LY', _('Libya')), ('LY', _('Libyan Arab Jamahiriya')),
('MA', _('Morocco')), ('MA', _('Morocco')),
('MC', _('Monaco')), ('MC', _('Monaco')),
('MD', _('Moldova')), ('MD', _('Moldova, Republic of')),
('ME', _('Montenegro')),
('MF', _('St. Martin')),
('MG', _('Madagascar')), ('MG', _('Madagascar')),
('MH', _('Marshall Islands')), ('MH', _('Marshall Islands')),
('MK', _('North Macedonia')),
('ML', _('Mali')), ('ML', _('Mali')),
('MM', _('Myanmar (Burma)')),
('MN', _('Mongolia')), ('MN', _('Mongolia')),
('MO', _('Macao SAR China')), ('MM', _('Myanmar')),
('MO', _('Macau')),
('MP', _('Northern Mariana Islands')), ('MP', _('Northern Mariana Islands')),
('MQ', _('Martinique')), ('MQ', _('Martinique')),
('MR', _('Mauritania')), ('MR', _('Mauritania')),
('MS', _('Montserrat')), ('MS', _('Monserrat')),
('MT', _('Malta')), ('MT', _('Malta')),
('MU', _('Mauritius')), ('MU', _('Mauritius')),
('MV', _('Maldives')), ('MV', _('Maldives')),
@ -184,17 +174,15 @@ COUNTRIES = (
('PK', _('Pakistan')), ('PK', _('Pakistan')),
('PL', _('Poland')), ('PL', _('Poland')),
('PM', _('St. Pierre & Miquelon')), ('PM', _('St. Pierre & Miquelon')),
('PN', _('Pitcairn Islands')), ('PN', _('Pitcairn')),
('PR', _('Puerto Rico')), ('PR', _('Puerto Rico')),
('PS', _('Palestinian Territories')),
('PT', _('Portugal')), ('PT', _('Portugal')),
('PW', _('Palau')), ('PW', _('Palau')),
('PY', _('Paraguay')), ('PY', _('Paraguay')),
('QA', _('Qatar')), ('QA', _('Qatar')),
('RE', _('Reunion')), ('RE', _('Reunion')),
('RO', _('Romania')), ('RO', _('Romania')),
('RS', _('Serbia')), ('RU', _('Russian Federation')),
('RU', _('Russia')),
('RW', _('Rwanda')), ('RW', _('Rwanda')),
('SA', _('Saudi Arabia')), ('SA', _('Saudi Arabia')),
('SB', _('Solomon Islands')), ('SB', _('Solomon Islands')),
@ -204,19 +192,17 @@ COUNTRIES = (
('SG', _('Singapore')), ('SG', _('Singapore')),
('SH', _('St. Helena')), ('SH', _('St. Helena')),
('SI', _('Slovenia')), ('SI', _('Slovenia')),
('SJ', _('Svalbard and Jan Mayen')), ('SJ', _('Svalbard & Jan Mayen Islands')),
('SK', _('Slovakia')), ('SK', _('Slovakia')),
('SL', _('Sierra Leone')), ('SL', _('Sierra Leone')),
('SM', _('San Marino')), ('SM', _('San Marino')),
('SN', _('Senegal')), ('SN', _('Senegal')),
('SO', _('Somalia')), ('SO', _('Somalia')),
('SR', _('Suriname')), ('SR', _('Suriname')),
('SS', _('South Sudan')),
('ST', _('Sao Tome & Principe')), ('ST', _('Sao Tome & Principe')),
('SV', _('El Salvador')), ('SV', _('El Salvador')),
('SX', _('Sint Maarten')), ('SY', _('Syrian Arab Republic')),
('SY', _('Syria')), ('SZ', _('Swaziland')),
('SZ', _('Eswatini')),
('TC', _('Turks & Caicos Islands')), ('TC', _('Turks & Caicos Islands')),
('TD', _('Chad')), ('TD', _('Chad')),
('TF', _('French Southern Territories')), ('TF', _('French Southern Territories')),
@ -224,34 +210,36 @@ COUNTRIES = (
('TH', _('Thailand')), ('TH', _('Thailand')),
('TJ', _('Tajikistan')), ('TJ', _('Tajikistan')),
('TK', _('Tokelau')), ('TK', _('Tokelau')),
('TL', _('Timor-Leste')),
('TM', _('Turkmenistan')), ('TM', _('Turkmenistan')),
('TN', _('Tunisia')), ('TN', _('Tunisia')),
('TO', _('Tonga')), ('TO', _('Tonga')),
('TP', _('East Timor')),
('TR', _('Turkey')), ('TR', _('Turkey')),
('TT', _('Trinidad & Tobago')), ('TT', _('Trinidad & Tobago')),
('TV', _('Tuvalu')), ('TV', _('Tuvalu')),
('TW', _('Taiwan')), ('TW', _('Taiwan, Province of China')),
('TZ', _('Tanzania')), ('TZ', _('Tanzania, United Republic of')),
('UA', _('Ukraine')), ('UA', _('Ukraine')),
('UG', _('Uganda')), ('UG', _('Uganda')),
('UM', _('U.S. Outlying Islands')), ('UM', _('United States Minor Outlying Islands')),
('US', _('United States')), ('US', _('United States of America')),
('UY', _('Uruguay')), ('UY', _('Uruguay')),
('UZ', _('Uzbekistan')), ('UZ', _('Uzbekistan')),
('VA', _('Vatican City')), ('VA', _('Vatican City State (Holy See)')),
('VC', _('St. Vincent & Grenadines')), ('VC', _('St. Vincent & the Grenadines')),
('VE', _('Venezuela')), ('VE', _('Venezuela')),
('VG', _('British Virgin Islands')), ('VG', _('British Virgin Islands')),
('VI', _('U.S. Virgin Islands')), ('VI', _('United States Virgin Islands')),
('VN', _('Vietnam')), ('VN', _('Viet Nam')),
('VU', _('Vanuatu')), ('VU', _('Vanuatu')),
('WF', _('Wallis & Futuna')), ('WF', _('Wallis & Futuna Islands')),
('WS', _('Samoa')), ('WS', _('Samoa')),
('YE', _('Yemen')), ('YE', _('Yemen')),
('YT', _('Mayotte')), ('YT', _('Mayotte')),
('YU', _('Yugoslavia')),
('ZA', _('South Africa')), ('ZA', _('South Africa')),
('ZM', _('Zambia')), ('ZM', _('Zambia')),
('ZR', _('Zaire')),
('ZW', _('Zimbabwe')), ('ZW', _('Zimbabwe')),
) )