diff --git a/Changelog b/Changelog index 04b699a9..a219bbee 100644 --- a/Changelog +++ b/Changelog @@ -1,23 +1,3 @@ -2.6.9: 2019-11-15 - * feature: Allow creating yearly subscriptions for Generic Products (MR!718) - Notes for deployment: - - do a db migrate for new column added to Generic Product model - ./manage.py migrate hosting -2.6.8: 2019-11-15 - * feature: [EU VAT] Add EU VAT feature for generic products (MR!717) - Notes for deployment: - - do a db migrate a to create VATRates table - ./manage.py migrate hosting - - load vat_rates.csv - ./manage.py import_vat_rates vat_rates.csv -2.6.7: 2019-11-04 - * bugfix: [admin] Improve dumpuser: show proper dates + bugfix - * bugfix: [admin] Improve fetch_stripe_bills: - - fix wrong assigment of string to num_invoice_created - variable, - - return None (do not handle the case) if we don't have an - order - * bugfix: [admin] Improve deleteuser: do not delete order, bill and vm_detail 2.6.6: 2019-11-04 * feature: [admin] Add dumpuser management command that dumps a user's data in json (MR!716) 2.6.5: 2019-09-24 diff --git a/datacenterlight/locale/de/LC_MESSAGES/django.po b/datacenterlight/locale/de/LC_MESSAGES/django.po index 6d58673a..b5ff3ca5 100644 --- a/datacenterlight/locale/de/LC_MESSAGES/django.po +++ b/datacenterlight/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-11-15 17:33+0000\n" +"POT-Creation-Date: 2019-07-03 11:18+0000\n" "PO-Revision-Date: 2018-03-30 23:22+0000\n" "Last-Translator: b'Anonymous User '\n" "Language-Team: LANGUAGE \n" @@ -20,7 +20,7 @@ msgstr "" "X-Translated-Using: django-rosetta 0.8.1\n" msgid "CMS Favicon" -msgstr "CMS Favicon" +msgstr "" #, python-format msgid "Your New VM %(vm_name)s at Data Center Light" @@ -52,7 +52,7 @@ msgid "Login" msgstr "Anmelden" msgid "Dashboard" -msgstr "Dashboard" +msgstr "" msgid "Thank you for contacting us." msgstr "Nachricht gesendet." @@ -64,7 +64,7 @@ msgid "Get in touch with us!" msgstr "Sende uns eine Nachricht." msgid "Name" -msgstr "Name" +msgstr "" msgid "Please enter your name." msgstr "Bitte gib Deinen Namen ein." @@ -108,7 +108,7 @@ msgid "Your account details are as follows" msgstr "Deine Account Details sind unten aufgelistet" msgid "Username" -msgstr "Benusername" +msgstr "Username" msgid "Your email address" msgstr "Deine E-Mail-Adresse" @@ -155,7 +155,7 @@ msgid "Please enter a value in range %(min_ram)s - 200." msgstr "Bitte gib einen Wert von %(min_ram)s bis 200 ein." msgid "VM hosting" -msgstr "VM Hosting" +msgstr "" msgid "month" msgstr "Monat" @@ -207,14 +207,14 @@ msgstr "" msgid "Only wants you to pay for what you actually need." msgstr "" -"Du möchtest nur das bezahlen, was du auch wirklich brauchst: Wähle deine " +"Möchte, dass du nur bezahlst, was du auch wirklich brauchst: Wähle deine " "Ressourcen individuell aus!
" msgid "" "Is creative, using a modern and alternative design for a data center in " "order to make it more sustainable and affordable at the same time." msgstr "" -"Es ist kreativ, da es sich ein modernes und alternatives Layout zu Nutze" +"Ist kreativ, indem es sich ein modernes und alternatives Layout zu Nutze " "macht um Nachhaltigkeit zu fördern und somit erschwingliche Preise bieten zu " "können.
" @@ -222,9 +222,9 @@ msgid "" "Cuts down the costs for you by using FOSS (Free Open Source Software) " "exclusively, wherefore we can save money from paying licenses." msgstr "" -"Um unnötige Kosten zu sparen werden, wird ausschliesslich Software auf" -"Basis von FOSS (Free Open Source Software) eingesetzt und dadurch können auf " -"Lizenzgebühren verzichtet werden.
" +"Sorgt dafür, dass unnötige Kosten erspart werden, indem es ausschliesslich " +"mit FOSS (Free Open Source Software) arbeitet und wir daher auf " +"Lizenzgebühren verzichten können.
" msgid "Scale out" msgstr "Skalierung" @@ -311,7 +311,7 @@ msgid "Billing Address" msgstr "Rechnungsadresse" msgid "Make a payment" -msgstr "Tätige eine Bezahlung" +msgstr "" msgid "Your Order" msgstr "Deine Bestellung" @@ -375,9 +375,6 @@ msgstr "Letzten" msgid "Type" msgstr "Typ" -msgid "Expiry" -msgstr "Ablaufdatum" - msgid "SELECT" msgstr "AUSWÄHLEN" @@ -418,23 +415,14 @@ msgstr "Bestellungsübersicht" msgid "Product" msgstr "Produkt" -msgid "Price" -msgstr "Preise" - -msgid "VAT for" -msgstr "MwSt für" - -msgid "Total Amount" -msgstr "Gesamtsumme" - msgid "Amount" -msgstr "Betrag" +msgstr "" msgid "Description" -msgstr "Beschreibung" +msgstr "" msgid "Recurring" -msgstr "Wiederholend" +msgstr "" msgid "Subtotal" msgstr "Zwischensumme" @@ -446,20 +434,12 @@ msgstr "Mehrwertsteuer" #| msgid "" #| "By clicking \"Place order\" this plan will charge your credit card " #| "account with %(total_price)s CHF/month" -msgid "" -"By clicking \"Place order\" this plan will charge your credit card account " -"with %(total_price)s CHF/year" -msgstr "" -"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit %(total_price)s " -"CHF pro Jahr belastet" - - msgid "" "By clicking \"Place order\" this plan will charge your credit card account " "with %(total_price)s CHF/month" msgstr "" -"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit %(total_price)s " -"CHF pro Monat belastet" +"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit " +"%(vm_total_price)s CHF pro Monat belastet" #, fuzzy, python-format #| msgid "" @@ -490,10 +470,10 @@ msgid "Hold tight, we are processing your request" msgstr "Bitte warten - wir verarbeiten Deine Anfrage gerade" msgid "OK" -msgstr "Ok" +msgstr "" msgid "Close" -msgstr "Schliessen" +msgstr "" msgid "Some problem encountered. Please try again later." msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal." @@ -505,7 +485,7 @@ msgid "Tech Stack" msgstr "Tech Stack" msgid "We are seriously open source." -msgstr "Wir sind vollends Open Source." +msgstr "Wir sind vollends opensource." msgid "" " Our full software stack is open source – We don't use anything that isn't " @@ -575,13 +555,13 @@ msgid "Starting from only 15CHF per month. Try now." msgstr "Unser Angebot beginnt bei 15 CHF pro Monat. Probier's jetzt aus!" msgid "Actions speak louder than words. Let's do it, try our VM now." -msgstr "Taten sagen mehr als Worte – Teste jetzt unsere VM!" +msgstr "Tagen sagen mehr als Worte – Teste jetzt unsere VM!" msgid "Invalid number of cores" msgstr "Ungültige Anzahle CPU-Kerne" msgid "Invalid calculator properties" -msgstr "Ungültige Berechnungseigenschaften" +msgstr "" msgid "Invalid RAM size" msgstr "Ungültige RAM-Grösse" @@ -591,7 +571,7 @@ msgstr "Ungültige Speicher-Grösse" #, python-brace-format msgid "Incorrect pricing name. Please contact support{support_email}" -msgstr "Ungültige Preisbezeichnung. Bitte kontaktiere den Support{support_email}" +msgstr "" #, python-brace-format msgid "{user} does not have permission to access the card" @@ -618,14 +598,11 @@ msgid "An error occurred while associating the card. Details: {details}" msgstr "" "Beim Verbinden der Karte ist ein Fehler aufgetreten. Details: {details}" -msgid " This is a monthly recurring plan." -msgstr "Dies ist ein monatlich wiederkehrender Plan." - -msgid " This is an yearly recurring plan." -msgstr "Dies ist ein jährlich wiederkehrender Plan." - msgid "Confirmation of your payment" -msgstr "Bestätigung deiner Zahlung" +msgstr "" + +msgid " This is a monthly recurring plan." +msgstr "" #, python-brace-format msgid "" @@ -636,8 +613,7 @@ msgid "" "\n" "Cheers,\n" "Your Data Center Light team" -msgstr "Hallo {name},\n" "\n" "vielen Dank für deine Bestellung!\n" "Wir haben deine Bezahlung in Höhe von {amount:.2f} CHF erhalten. {recurring}\n" "\n" "Grüsse\n" -"Dein Data Center Light Team" +msgstr "" msgid "Thank you for the payment." msgstr "Danke für Deine Bestellung." @@ -645,7 +621,7 @@ msgstr "Danke für Deine Bestellung." msgid "" "You will soon receive a confirmation email of the payment. You can always " "contact us at info@ungleich.ch for any question that you may have." -msgstr "Du wirst bald eine Bestätigungs-E-Mail über die Zahlung erhalten. Du kannst jederzeit unter info@ungleich.ch kontaktieren." +msgstr "" msgid "Thank you for the order." msgstr "Danke für Deine Bestellung." @@ -668,6 +644,9 @@ msgstr "" #~ msgid "Card Number" #~ msgstr "Kreditkartennummer" +#~ msgid "Expiry Date" +#~ msgstr "Ablaufdatum" + #~ msgid "" #~ "You are not making any payment yet. After placing your order, you will be " #~ "taken to the Submit Payment Page." @@ -676,6 +655,9 @@ msgstr "" #~ "ausgelöst, nachdem Du die Bestellung auf der nächsten Seite bestätigt " #~ "hast." +#~ msgid "Pricing" +#~ msgstr "Preise" + #~ msgid "Order VM" #~ msgstr "VM bestellen" diff --git a/datacenterlight/management/commands/deleteuser.py b/datacenterlight/management/commands/deleteuser.py index d4ccba29..1d57aa41 100644 --- a/datacenterlight/management/commands/deleteuser.py +++ b/datacenterlight/management/commands/deleteuser.py @@ -1,17 +1,14 @@ import logging -import sys -import uuid - import oca +import sys import stripe + from django.core.management.base import BaseCommand - -from hosting.models import ( - UserCardDetail, UserHostingKey -) from membership.models import CustomUser, DeletedUser +from hosting.models import ( + HostingOrder, HostingBill, VMDetail, UserCardDetail, UserHostingKey +) from opennebula_api.models import OpenNebulaManager - logger = logging.getLogger(__name__) @@ -82,6 +79,75 @@ class Command(BaseCommand): else: logger.error("Error while deleting the StripeCustomer") + hosting_orders = HostingOrder.objects.filter( + customer=stripe_customer.id + ) + + vm_ids = [] + for order in hosting_orders: + vm_ids.append(order.vm_id) + + # Delete Billing Address + if order.billing_address is not None: + logger.debug( + "Billing Address {} associated with {} deleted" + "".format(order.billing_address.id, email) + ) + order.billing_address.delete() + else: + logger.error( + "Error while deleting the billing_address") + + # Delete order + if order is not None: + logger.debug( + "Order {} associated with {} deleted" + "".format(order.id, email) + ) + order.delete() + else: + logger.error( + "Error while deleting the Order") + + hosting_bills = HostingBill.objects.filter( + customer=stripe_customer.id + ) + + # delete hosting bills + for bill in hosting_bills: + if bill.billing_address is not None: + logger.debug( + "HostingBills billing address {} associated with {} deleted" + "".format(bill.billing_address.id, email) + ) + bill.billing_address.delete() + else: + logger.error( + "Error while deleting the HostingBill's Billing address") + + if bill is not None: + logger.debug( + "HostingBill {} associated with {} deleted" + "".format(bill.id, email) + ) + bill.delete() + else: + logger.error( + "Error while deleting the HostingBill") + + # delete VMDetail + for vm_id in vm_ids: + vm_detail = VMDetail.objects.get(vm_id=vm_id) + if vm_detail is not None: + logger.debug( + "vm_detail {} associated with {} deleted" + "".format(vm_detail.id, email) + ) + vm_detail.delete() + else: + logger.error( + "Error while deleting the vm_detail") + # delete UserCardDetail ucds = UserCardDetail.objects.filter( stripe_customer=stripe_customer @@ -113,10 +179,8 @@ class Command(BaseCommand): user_id = cus_user.id ) - # reset CustomUser - cus_user.email = str(uuid.uuid4()) - cus_user.validated = 0 - cus_user.save() + # delete CustomUser + cus_user.delete() # remove user from OpenNebula manager = OpenNebulaManager() diff --git a/datacenterlight/management/commands/dumpuser.py b/datacenterlight/management/commands/dumpuser.py index 24857dec..aa86371e 100644 --- a/datacenterlight/management/commands/dumpuser.py +++ b/datacenterlight/management/commands/dumpuser.py @@ -1,6 +1,6 @@ -import json import logging import sys +from pprint import pprint from django.core.management.base import BaseCommand from membership.models import CustomUser @@ -19,6 +19,7 @@ class Command(BaseCommand): def handle(self, *args, **options): try: for email in options['customer_email']: + logger.debug("Creating dump for the user {}".format(email)) try: cus_user = CustomUser.objects.get(email=email) except CustomUser.DoesNotExist as dne: @@ -37,7 +38,7 @@ class Command(BaseCommand): vm_ids.append(order.vm_id) order_dict["VM_ID"] = order.vm_id order_dict["Order Nr."] = order.id - order_dict["Created On"] = str(order.created_at) + order_dict["Created On"] = str(order.created_on) order_dict["Price"] = order.price order_dict["Payment card details"] = { "last4": order.last4, @@ -81,7 +82,7 @@ class Command(BaseCommand): "IPv6": vm_detail.ipv6, "OS": vm_detail.configuration, } - order_dict["Terminated on"] = str(vm_detail.terminated_at) + order_dict["Terminated on"] = vm_detail.terminated_at orders_dict[order.vm_id] = order_dict @@ -115,9 +116,10 @@ class Command(BaseCommand): "Name": uhk.name, "Created on": str(uhk.created_at) } - if uhk.private_key: + if uhk.private_key is not None: key["Private key"] = uhk.private_key keys[uhk.name] = key + print("User {} dump is follows:") output_dict = { "User details": { "Name": cus_user.name, @@ -129,6 +131,7 @@ class Command(BaseCommand): "Payment cards": cards, "SSH Keys": keys } - print(json.dumps(output_dict, indent=4)) + pprint(output_dict) + logger.debug("Dumped user {} SUCCESSFULLY.".format(email)) except Exception as e: print(" *** Error occurred. Details {}".format(str(e))) diff --git a/datacenterlight/templates/datacenterlight/order_detail.html b/datacenterlight/templates/datacenterlight/order_detail.html index bc8e7562..8a444bef 100644 --- a/datacenterlight/templates/datacenterlight/order_detail.html +++ b/datacenterlight/templates/datacenterlight/order_detail.html @@ -55,25 +55,10 @@

- {% if generic_payment_details.vat_rate > 0 %} -

- {% trans "Price" %}: - CHF {{generic_payment_details.amount_before_vat|floatformat:2|intcomma}} -

-

- {% trans "VAT for" %} {{generic_payment_details.vat_country}} ({{generic_payment_details.vat_rate}}%) : - CHF {{generic_payment_details.vat_amount|floatformat:2|intcomma}} -

-

- {% trans "Total Amount" %} : - CHF {{generic_payment_details.amount|floatformat:2|intcomma}} -

- {% else %}

{% trans "Amount" %}: CHF {{generic_payment_details.amount|floatformat:2|intcomma}}

- {% endif %} {% if generic_payment_details.description %}

{% trans "Description" %}: @@ -154,11 +139,7 @@

{% if generic_payment_details %} {% if generic_payment_details.recurring %} - {% if generic_payment_details.recurring_interval == 'year' %} -
{% blocktrans with total_price=generic_payment_details.amount|floatformat:2|intcomma %}By clicking "Place order" this plan will charge your credit card account with {{total_price}} CHF/year{% endblocktrans %}.
- {% else %} -
{% blocktrans with total_price=generic_payment_details.amount|floatformat:2|intcomma %}By clicking "Place order" this plan will charge your credit card account with {{total_price}} CHF/month{% endblocktrans %}.
- {% endif %} +
{% blocktrans with total_price=generic_payment_details.amount|floatformat:2|intcomma %}By clicking "Place order" this plan will charge your credit card account with {{total_price}} CHF/month{% endblocktrans %}.
{% else %}
{% blocktrans with total_price=generic_payment_details.amount|floatformat:2|intcomma %}By clicking "Place order" this payment will charge your credit card account with a one time amount of {{total_price}} CHF{% endblocktrans %}.
{% endif %} diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 44226abb..ae649623 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -26,9 +26,7 @@ from utils.forms import ( BillingAddressForm, BillingAddressFormSignup, UserBillingAddressForm, BillingAddress ) -from utils.hosting_utils import ( - get_vm_price_with_vat, get_all_public_keys, get_vat_rate_for_country -) +from utils.hosting_utils import get_vm_price_with_vat, get_all_public_keys from utils.stripe_utils import StripeUtils from utils.tasks import send_plain_email_task from .cms_models import DCLCalculatorPluginModel @@ -414,21 +412,10 @@ class PaymentOrderView(FormView): product = generic_payment_form.cleaned_data.get( 'product_name' ) - user_country_vat_rate = get_vat_rate_for_country( - address_form.cleaned_data["country"] - ) gp_details = { "product_name": product.product_name, - "vat_rate": user_country_vat_rate * 100, - "vat_amount": round( - float(product.product_price) * - user_country_vat_rate, 2), - "vat_country": address_form.cleaned_data["country"], - "amount_before_vat": round( - float(product.product_price), 2), - "amount": product.get_actual_price( - vat_rate=get_vat_rate_for_country( - address_form.cleaned_data["country"]) + "amount": generic_payment_form.cleaned_data.get( + 'amount' ), "recurring": generic_payment_form.cleaned_data.get( 'recurring' @@ -437,9 +424,7 @@ class PaymentOrderView(FormView): 'description' ), "product_id": product.id, - "product_slug": product.product_slug, - "recurring_interval": - product.product_subscription_interval + "product_slug": product.product_slug } request.session["generic_payment_details"] = ( gp_details @@ -758,7 +743,6 @@ class OrderConfirmationView(DetailView, FormView): if ('generic_payment_type' not in request.session or (request.session['generic_payment_details']['recurring'])): - recurring_interval = 'month' if 'generic_payment_details' in request.session: amount_to_be_charged = ( round( @@ -771,10 +755,6 @@ class OrderConfirmationView(DetailView, FormView): amount_to_be_charged ) stripe_plan_id = plan_name - recurring_interval = request.session['generic_payment_details']['recurring_interval'] - if recurring_interval == "year": - plan_name = "{}-yearly".format(plan_name) - stripe_plan_id = plan_name else: template = request.session.get('template') specs = request.session.get('specs') @@ -801,9 +781,7 @@ class OrderConfirmationView(DetailView, FormView): stripe_plan = stripe_utils.get_or_create_stripe_plan( amount=amount_to_be_charged, name=plan_name, - stripe_plan_id=stripe_plan_id, - interval=recurring_interval - ) + stripe_plan_id=stripe_plan_id) subscription_result = stripe_utils.subscribe_customer_to_plan( stripe_api_cus_id, [{"plan": stripe_plan.get( @@ -994,9 +972,6 @@ class OrderConfirmationView(DetailView, FormView): 'reply_to': [context['email']], } send_plain_email_task.delay(email_data) - recurring_text = _(" This is a monthly recurring plan.") - if gp_details['recurring_interval'] == "year": - recurring_text = _(" This is an yearly recurring plan.") email_data = { 'subject': _("Confirmation of your payment"), @@ -1010,7 +985,7 @@ class OrderConfirmationView(DetailView, FormView): name=user.get('name'), amount=gp_details['amount'], recurring=( - recurring_text + _(' This is a monthly recurring plan.') if gp_details['recurring'] else '' ) ) diff --git a/hosting/forms.py b/hosting/forms.py index 947cee44..d98d258f 100644 --- a/hosting/forms.py +++ b/hosting/forms.py @@ -109,14 +109,9 @@ class ProductPaymentForm(GenericPaymentForm): ) ) if self.product.product_is_subscription: - payment_type = "month" - if self.product.product_subscription_interval == "month": - payment_type = _('Monthly subscription') - elif self.product.product_subscription_interval == "year": - payment_type = _('Yearly subscription') self.fields['amount'].label = "{amt} ({payment_type})".format( amt=_('Amount in CHF'), - payment_type=payment_type + payment_type=_('Monthly subscription') ) else: self.fields['amount'].label = "{amt} ({payment_type})".format( diff --git a/hosting/locale/de/LC_MESSAGES/django.po b/hosting/locale/de/LC_MESSAGES/django.po index 08bcdd7a..5c719457 100644 --- a/hosting/locale/de/LC_MESSAGES/django.po +++ b/hosting/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-11-15 16:40+0000\n" +"POT-Creation-Date: 2019-09-15 03:39+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -28,31 +28,28 @@ msgid "User does not exist" msgstr "Der Benutzer existiert nicht" msgid "Choose a product" -msgstr "Wähle ein Produkt" +msgstr "" msgid "Amount in CHF" msgstr "Betrag" msgid "Recurring monthly" -msgstr "monatlich wiederkehrend" +msgstr "" msgid "Amount field does not match" -msgstr "Betragsfeld stimmt nicht überein" +msgstr "" msgid "Recurring field does not match" -msgstr "Betragsfeld stimmt nicht überein" +msgstr "" msgid "Product name" msgstr "Produkt" msgid "Monthly subscription" -msgstr "Monatliches Abonnement" - -msgid "Yearly subscription" -msgstr "Jährliches Abonnement" +msgstr "" msgid "One time payment" -msgstr "Einmalzahlung" +msgstr "" msgid "Confirm Password" msgstr "Passwort Bestätigung" @@ -76,7 +73,7 @@ msgid "Please input a proper SSH key" msgstr "Bitte verwende einen gültigen SSH-Key" msgid "Comma not accepted in the name of the key" -msgstr "Komma im Namen des Keys wird nicht akzeptiert" +msgstr "" msgid "All Rights Reserved" msgstr "Alle Rechte vorbehalten" @@ -242,8 +239,7 @@ msgid "You can view your VM detail by clicking the button below." msgstr "Um die Rechnung zu sehen, klicke auf den Button unten." msgid "You can log in to your VM by the username puffy." -msgstr "" -"Du kannst Dich auf Deiner VM mit dem user puffy einloggen." +msgstr "Du kannst Dich auf Deiner VM mit dem user puffy einloggen." msgid "View Detail" msgstr "Details anzeigen" @@ -404,19 +400,13 @@ msgid "Amount" msgstr "Betrag" msgid "Description" -msgstr "Beschreibung" +msgstr "" msgid "Recurring" -msgstr "wiederkehrend" - -msgid "of" -msgstr "von" - -msgid "each year" -msgstr "jedes Jahr" +msgstr "" msgid "of every month" -msgstr "jeden Monat" +msgstr "" msgid "BACK TO LIST" msgstr "ZURÜCK ZUR LISTE" @@ -428,13 +418,16 @@ msgid "VM ID" msgstr "" msgid "IP Address" -msgstr "IP-Adresse" +msgstr "" msgid "See Invoice" msgstr "Siehe Rechnung" msgid "Page" -msgstr "Seite" +msgstr "" + +msgid "of" +msgstr "" msgid "Log in" msgstr "Anmelden" @@ -496,7 +489,7 @@ msgid "Hold tight, we are processing your request" msgstr "Bitte warten - wir bearbeiten Deine Anfrage gerade" msgid "OK" -msgstr "Ok" +msgstr "" msgid "Close" msgstr "Schliessen" @@ -852,7 +845,7 @@ msgstr "Ungültige Speicher-Grösse" #, python-brace-format msgid "Incorrect pricing name. Please contact support{support_email}" -msgstr "Ungültige Preisbezeichnung. Bitte kontaktiere den Support{support_email}" +msgstr "" msgid "" "We could not find the requested VM. Please " @@ -871,7 +864,7 @@ msgstr "Fehler beenden VM" msgid "" "VM terminate action timed out. Please contact support@datacenterlight.ch for " "further information." -msgstr "VM beendet wegen Zeitüberschreitung. Bitte kontaktiere support@datacenterlight.ch für weitere Informationen." +msgstr "" #, python-format msgid "Virtual Machine %(vm_name)s Cancelled" diff --git a/hosting/management/commands/fetch_stripe_bills.py b/hosting/management/commands/fetch_stripe_bills.py index 1e4d1ab3..20f1cbe0 100644 --- a/hosting/management/commands/fetch_stripe_bills.py +++ b/hosting/management/commands/fetch_stripe_bills.py @@ -50,12 +50,7 @@ class Command(BaseCommand): logger.debug("Invoice %s exists already. Not importing." % invoice['invoice_id']) except MonthlyHostingBill.DoesNotExist as dne: logger.debug("Invoice id %s does not exist" % invoice['invoice_id']) - - if MonthlyHostingBill.create(invoice) is not None: - num_invoice_created += 1 - else: - logger.error("Did not import invoice for %s" - "" % str(invoice)) + num_invoice_created += 1 if MonthlyHostingBill.create(invoice) is not None else logger.error("Did not import invoice for %s" % str(invoice)) self.stdout.write( self.style.SUCCESS("Number of invoices imported = %s" % num_invoice_created) ) diff --git a/hosting/management/commands/import_vat_rates.py b/hosting/management/commands/import_vat_rates.py deleted file mode 100644 index f779133d..00000000 --- a/hosting/management/commands/import_vat_rates.py +++ /dev/null @@ -1,44 +0,0 @@ -from django.core.management.base import BaseCommand -import csv -from hosting.models import VATRates - - -class Command(BaseCommand): - help = '''Imports VAT Rates. Assume vat rates of format https://github.com/kdeldycke/vat-rates/blob/master/vat_rates.csv''' - - def add_arguments(self, parser): - parser.add_argument('csv_file', nargs='+', type=str) - - def handle(self, *args, **options): - try: - for c_file in options['csv_file']: - print("c_file = %s" % c_file) - with open(c_file, mode='r') as csv_file: - csv_reader = csv.DictReader(csv_file) - line_count = 0 - for row in csv_reader: - if line_count == 0: - line_count += 1 - obj, created = VATRates.objects.get_or_create( - start_date=row["start_date"], - stop_date=row["stop_date"] if row["stop_date"] is not "" else None, - territory_codes=row["territory_codes"], - currency_code=row["currency_code"], - rate=row["rate"], - rate_type=row["rate_type"], - description=row["description"] - ) - if created: - self.stdout.write(self.style.SUCCESS( - '%s. %s - %s - %s - %s' % ( - line_count, - obj.start_date, - obj.stop_date, - obj.territory_codes, - obj.rate - ) - )) - line_count+=1 - - except Exception as e: - print(" *** Error occurred. Details {}".format(str(e))) diff --git a/hosting/migrations/0057_vatrates.py b/hosting/migrations/0057_vatrates.py deleted file mode 100644 index 494974c6..00000000 --- a/hosting/migrations/0057_vatrates.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.4 on 2019-11-15 05:16 -from __future__ import unicode_literals - -from django.db import migrations, models -import utils.mixins - - -class Migration(migrations.Migration): - - dependencies = [ - ('hosting', '0056_auto_20191026_0454'), - ] - - operations = [ - migrations.CreateModel( - name='VATRates', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('start_date', models.DateField(blank=True, null=True)), - ('stop_date', models.DateField(blank=True, null=True)), - ('territory_codes', models.TextField(blank=True, default='')), - ('currency_code', models.CharField(max_length=10)), - ('rate', models.FloatField()), - ('rate_type', models.TextField(blank=True, default='')), - ('description', models.TextField(blank=True, default='')), - ], - bases=(utils.mixins.AssignPermissionsMixin, models.Model), - ), - ] diff --git a/hosting/migrations/0058_genericproduct_product_subscription_interval.py b/hosting/migrations/0058_genericproduct_product_subscription_interval.py deleted file mode 100644 index c994ef16..00000000 --- a/hosting/migrations/0058_genericproduct_product_subscription_interval.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.4 on 2019-11-15 14:57 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('hosting', '0057_vatrates'), - ] - - operations = [ - migrations.AddField( - model_name='genericproduct', - name='product_subscription_interval', - field=models.CharField(default='month', help_text='Choose between `year` and `month`', max_length=10), - ), - ] diff --git a/hosting/models.py b/hosting/models.py index 6050339a..c9ca5efe 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -1,4 +1,3 @@ -import decimal import json import logging import os @@ -79,17 +78,13 @@ class GenericProduct(AssignPermissionsMixin, models.Model): product_price = models.DecimalField(max_digits=6, decimal_places=2) product_vat = models.DecimalField(max_digits=6, decimal_places=4, default=0) product_is_subscription = models.BooleanField(default=True) - product_subscription_interval = models.CharField( - max_length=10, default="month", - help_text="Choose between `year` and `month`") def __str__(self): return self.product_name - def get_actual_price(self, vat_rate=None): - VAT = vat_rate if vat_rate is not None else self.product_vat + def get_actual_price(self): return round( - float(self.product_price) + float(self.product_price) * float(VAT), 2 + self.product_price + (self.product_price * self.product_vat), 2 ) @@ -324,10 +319,7 @@ class MonthlyHostingBill(AssignPermissionsMixin, models.Model): logger.debug("Neither subscription id nor vm_id available") logger.debug("Can't import invoice") return None - if args['order'] is None: - logger.error( - "Order is None for {}".format(args['invoice_id'])) - return None + instance = cls.objects.create( created=datetime.utcfromtimestamp( args['created']).replace(tzinfo=pytz.utc), @@ -712,13 +704,3 @@ class UserCardDetail(AssignPermissionsMixin, models.Model): return ucd except UserCardDetail.DoesNotExist: return None - - -class VATRates(AssignPermissionsMixin, models.Model): - start_date = models.DateField(blank=True, null=True) - stop_date = models.DateField(blank=True, null=True) - territory_codes = models.TextField(blank=True, default='') - currency_code = models.CharField(max_length=10) - rate = models.FloatField() - rate_type = models.TextField(blank=True, default='') - description = models.TextField(blank=True, default='') \ No newline at end of file diff --git a/hosting/templates/hosting/invoice_detail.html b/hosting/templates/hosting/invoice_detail.html index b9a3e742..d757d476 100644 --- a/hosting/templates/hosting/invoice_detail.html +++ b/hosting/templates/hosting/invoice_detail.html @@ -195,13 +195,8 @@ {% if invoice.order.subscription_id %}

{% trans "Recurring" %}: - {% if invoice.order.generic_product.product_subscription_interval == 'year' %} - {{invoice.order.created_at|date:'d'|ordinal}} {% trans "of" %} {{invoice.order.created_at|date:'b'|title}} - {% trans "each year" %} - {% else %} - {{invoice.order.created_at|date:'d'|ordinal}} + {{invoice.order.created_at|date:'d'|ordinal}} {% trans "of every month" %} - {% endif %}

{% endif %}
diff --git a/hosting/templates/hosting/order_detail.html b/hosting/templates/hosting/order_detail.html index 2775882d..a84e4e4f 100644 --- a/hosting/templates/hosting/order_detail.html +++ b/hosting/templates/hosting/order_detail.html @@ -186,13 +186,7 @@ {% if order.subscription_id %}

{% trans "Recurring" %}: - {% if order.generic_product.product_subscription_interval == 'year' %} - {{order.created_at|date:'d'|ordinal}} {% trans "of" %} {{order.created_at|date:'b'|title}} - {% trans "each year" %} - {% else %} - {{order.created_at|date:'d'|ordinal}} - {% trans "of every month" %} - {% endif %} + {{order.created_at|date:'d'|ordinal}} {% trans "of every month" %}

{% endif %}
diff --git a/hosting/views.py b/hosting/views.py index 25303b99..bb00978d 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -1268,10 +1268,6 @@ class InvoiceDetailView(LoginRequiredMixin, DetailView): context['vm']['total_price'] = ( price + vat - discount['amount'] ) - except TypeError: - logger.error("Type error. Probably we " - "came from a generic product. " - "Invoice ID %s" % obj.invoice_id) except WrongIdError: logger.error("WrongIdError while accessing " "invoice {}".format(obj.invoice_id)) diff --git a/utils/hosting_utils.py b/utils/hosting_utils.py index 9c0243e4..b3c47e6e 100644 --- a/utils/hosting_utils.py +++ b/utils/hosting_utils.py @@ -5,7 +5,7 @@ import subprocess from oca.pool import WrongIdError from datacenterlight.models import VMPricing -from hosting.models import UserHostingKey, VMDetail, VATRates +from hosting.models import UserHostingKey, VMDetail from opennebula_api.serializers import VirtualMachineSerializer logger = logging.getLogger(__name__) @@ -150,20 +150,6 @@ def ping_ok(host_ipv6): return True -def get_vat_rate_for_country(country): - vat_rate = None - try: - vat_rate = VATRates.objects.get( - territory_codes=country, start_date__isnull=False, stop_date=None - ) - logger.debug("VAT rate for %s is %s" % (country, vat_rate.rate)) - return vat_rate.rate - except VATRates.DoesNotExist as dne: - logger.debug(str(dne)) - logger.debug("Did not find VAT rate for %s, returning 0" % country) - return 0 - - class HostingUtils: @staticmethod def clear_items_from_list(from_list, items_list): diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py index e2bdb983..4334d6cf 100644 --- a/utils/stripe_utils.py +++ b/utils/stripe_utils.py @@ -226,8 +226,7 @@ class StripeUtils(object): return charge @handleStripeError - def get_or_create_stripe_plan(self, amount, name, stripe_plan_id, - interval=""): + def get_or_create_stripe_plan(self, amount, name, stripe_plan_id): """ This function checks if a StripePlan with the given stripe_plan_id already exists. If it exists then the function @@ -239,10 +238,6 @@ class StripeUtils(object): :param stripe_plan_id: The id of the Stripe plan to be created. Use get_stripe_plan_id_string function to obtain the name of the plan to be created - :param interval: str representing the interval of the Plan - Specifies billing frequency. Either day, week, month or year. - Ref: https://stripe.com/docs/api/plans/create#create_plan-interval - The default is month :return: The StripePlan object if it exists else creates a Plan object in Stripe and a local StripePlan and returns it. Returns None in case of Stripe error @@ -250,7 +245,6 @@ class StripeUtils(object): _amount = float(amount) amount = int(_amount * 100) # stripe amount unit, in cents stripe_plan_db_obj = None - plan_interval = interval if interval is not "" else self.INTERVAL try: stripe_plan_db_obj = StripePlan.objects.get( stripe_plan_id=stripe_plan_id) @@ -258,7 +252,7 @@ class StripeUtils(object): try: self.stripe.Plan.create( amount=amount, - interval=plan_interval, + interval=self.INTERVAL, name=name, currency=self.CURRENCY, id=stripe_plan_id) diff --git a/vat_rates.csv b/vat_rates.csv deleted file mode 100644 index 4a3ec440..00000000 --- a/vat_rates.csv +++ /dev/null @@ -1,318 +0,0 @@ -start_date,stop_date,territory_codes,currency_code,rate,rate_type,description -2011-01-04,,AI,XCD,0,standard,Anguilla (British overseas territory) is exempted of VAT. -1984-01-01,,AT,EUR,0.2,standard,Austria (member state) standard VAT rate. -1976-01-01,1984-01-01,AT,EUR,0.18,standard, -1973-01-01,1976-01-01,AT,EUR,0.16,standard, -1984-01-01,,"AT-6691 -DE-87491",EUR,0.19,standard,Jungholz (Austrian town) special VAT rate. -1984-01-01,,"AT-6991 -AT-6992 -AT-6993 -DE-87567 -DE-87568 -DE-87569",EUR,0.19,standard,Mittelberg (Austrian town) special VAT rate. -1996-01-01,,BE,EUR,0.21,standard,Belgium (member state) standard VAT rate. -1994-01-01,1996-01-01,BE,EUR,0.205,standard, -1992-04-01,1994-01-01,BE,EUR,0.195,standard, -1983-01-01,1992-04-01,BE,EUR,0.19,standard, -1981-07-01,1983-01-01,BE,EUR,0.17,standard, -1978-07-01,1981-07-01,BE,EUR,0.16,standard, -1971-07-01,1978-07-01,BE,EUR,0.18,standard, -1999-01-01,,BG,BGN,0.2,standard,Bulgaria (member state) standard VAT rate. -1996-07-01,1999-01-01,BG,BGN,0.22,standard, -1994-04-01,1996-07-01,BG,BGN,0.18,standard, -2011-01-04,,BM,BMD,0,standard,Bermuda (British overseas territory) is exempted of VAT. -2014-01-13,,"CY -GB-BFPO 57 -GB-BFPO 58 -GB-BFPO 59 -UK-BFPO 57 -UK-BFPO 58 -UK-BFPO 59",EUR,0.19,standard,"Cyprus (member state) standard VAT rate. -Akrotiri and Dhekelia (British overseas territory) is subjected to Cyprus' standard VAT rate." -2013-01-14,2014-01-13,CY,EUR,0.18,standard, -2012-03-01,2013-01-14,CY,EUR,0.17,standard, -2003-01-01,2012-03-01,CY,EUR,0.15,standard, -2002-07-01,2003-01-01,CY,EUR,0.13,standard, -2000-07-01,2002-07-01,CY,EUR,0.1,standard, -1993-10-01,2000-07-01,CY,EUR,0.08,standard, -1992-07-01,1993-10-01,CY,EUR,0.05,standard, -2013-01-01,,CZ,CZK,0.21,standard,Czech Republic (member state) standard VAT rate. -2010-01-01,2013-01-01,CZ,CZK,0.2,standard, -2004-05-01,2010-01-01,CZ,CZK,0.19,standard, -1995-01-01,2004-05-01,CZ,CZK,0.22,standard, -1993-01-01,1995-01-01,CZ,CZK,0.23,standard, -2007-01-01,,DE,EUR,0.19,standard,Germany (member state) standard VAT rate. -1998-04-01,2007-01-01,DE,EUR,0.16,standard, -1993-01-01,1998-04-01,DE,EUR,0.15,standard, -1983-07-01,1993-01-01,DE,EUR,0.14,standard, -1979-07-01,1983-07-01,DE,EUR,0.13,standard, -1978-01-01,1979-07-01,DE,EUR,0.12,standard, -1968-07-01,1978-01-01,DE,EUR,0.11,standard, -1968-01-01,1968-07-01,DE,EUR,0.1,standard, -2007-01-01,,DE-27498,EUR,0,standard,Heligoland (German island) is exempted of VAT. -2007-01-01,,"DE-78266 -CH-8238",EUR,0,standard,Busingen am Hochrhein (German territory) is exempted of VAT. -1992-01-01,,DK,DKK,0.25,standard,Denmark (member state) standard VAT rate. -1980-06-30,1992-01-01,DK,DKK,0.22,standard, -1978-10-30,1980-06-30,DK,DKK,0.2025,standard, -1977-10-03,1978-10-30,DK,DKK,0.18,standard, -1970-06-29,1977-10-03,DK,DKK,0.15,standard, -1968-04-01,1970-06-29,DK,DKK,0.125,standard, -1967-07-03,1968-04-01,DK,DKK,0.1,standard, -2009-07-01,,EE,EUR,0.2,standard,Estonia (member state) standard VAT rate. -1993-01-01,2009-07-01,EE,EUR,0.18,standard, -1991-01-01,1993-01-01,EE,EUR,0.1,standard, -2016-06-01,,"GR -EL",EUR,0.24,standard,Greece (member state) standard VAT rate. -2010-07-01,2016-06-01,"GR -EL",EUR,0.23,standard, -2010-03-15,2010-07-01,"GR -EL",EUR,0.21,standard, -2005-04-01,2010-03-15,"GR -EL",EUR,0.19,standard, -1990-04-28,2005-04-01,"GR -EL",EUR,0.18,standard, -1988-01-01,1990-04-28,"GR -EL",EUR,0.16,standard, -1987-01-01,1988-01-01,"GR -EL",EUR,0.18,standard, -2012-09-01,,ES,EUR,0.21,standard,Spain (member state) standard VAT rate. -2010-07-01,2012-09-01,ES,EUR,0.18,standard, -1995-01-01,2010-07-01,ES,EUR,0.16,standard, -1992-08-01,1995-01-01,ES,EUR,0.15,standard, -1992-01-01,1992-08-01,ES,EUR,0.13,standard, -1986-01-01,1992-01-01,ES,EUR,0.12,standard, -2012-09-01,,"ES-CN -ES-GC -ES-TF -IC",EUR,0,standard,Canary Islands (Spanish autonomous community) is exempted of VAT. -2012-09-01,,"ES-ML -ES-CE -EA",EUR,0,standard,Ceuta and Melilla (Spanish autonomous cities) is exempted of VAT. -2013-01-01,,FI,EUR,0.24,standard,Finland (member state) standard VAT rate. -2010-07-01,2013-01-01,FI,EUR,0.23,standard, -1994-06-01,2010-07-01,FI,EUR,0.22,standard, -2013-01-01,,"FI-01 -AX",EUR,0,standard,Aland Islands (Finish autonomous region) is exempted of VAT. -2011-01-04,,FK,FKP,0,standard,Falkland Islands (British overseas territory) is exempted of VAT. -1992-01-01,,FO,DKK,0,standard,Faroe Islands (Danish autonomous country) is exempted of VAT. -2014-01-01,,"FR -MC",EUR,0.2,standard,"France (member state) standard VAT rate. -Monaco (sovereign city-state) is member of the EU VAT area and subjected to France's standard VAT rate." -2000-04-01,2014-01-01,"FR -MC",EUR,0.196,standard, -1995-08-01,2000-04-01,"FR -MC",EUR,0.206,standard, -1982-07-01,1995-08-01,"FR -MC",EUR,0.186,standard, -1977-01-01,1982-07-01,"FR -MC",EUR,0.176,standard, -1973-01-01,1977-01-01,"FR -MC",EUR,0.2,standard, -1970-01-01,1973-01-01,"FR -MC",EUR,0.23,standard, -1968-12-01,1970-01-01,"FR -MC",EUR,0.19,standard, -1968-01-01,1968-12-01,"FR -MC",EUR,0.1666,standard, -2014-01-01,,"FR-BL -BL",EUR,0,standard,Saint Barthelemy (French overseas collectivity) is exempted of VAT. -2014-01-01,,"FR-GF -GF",EUR,0,standard,Guiana (French overseas department) is exempted of VAT. -2014-01-01,,"FR-GP -GP",EUR,0.085,standard,Guadeloupe (French overseas department) special VAT rate. -2014-01-01,,"FR-MF -MF",EUR,0,standard,Saint Martin (French overseas collectivity) is subjected to France's standard VAT rate. -2014-01-01,,"FR-MQ -MQ",EUR,0.085,standard,Martinique (French overseas department) special VAT rate. -2014-01-01,,"FR-NC -NC",XPF,0,standard,New Caledonia (French special collectivity) is exempted of VAT. -2014-01-01,,"FR-PF -PF",XPF,0,standard,French Polynesia (French overseas collectivity) is exempted of VAT. -2014-01-01,,"FR-PM -PM",EUR,0,standard,Saint Pierre and Miquelon (French overseas collectivity) is exempted of VAT. -2014-01-01,,"FR-RE -RE",EUR,0.085,standard,Reunion (French overseas department) special VAT rate. -2014-01-01,,"FR-TF -TF",EUR,0,standard,French Southern and Antarctic Lands (French overseas territory) is exempted of VAT. -2014-01-01,,"FR-WF -WF",XPF,0,standard,Wallis and Futuna (French overseas collectivity) is exempted of VAT. -2014-01-01,,"FR-YT -YT",EUR,0,standard,Mayotte (French overseas department) is exempted of VAT. -2011-01-04,,GG,GBP,0,standard,Guernsey (British Crown dependency) is exempted of VAT. -2011-01-04,,GI,GIP,0,standard,Gibraltar (British overseas territory) is exempted of VAT. -1992-01-01,,GL,DKK,0,standard,Greenland (Danish autonomous country) is exempted of VAT. -2010-07-01,2016-06-01,"GR-34007 -EL-34007",EUR,0.16,standard,Skyros (Greek island) special VAT rate. -2010-07-01,2016-06-01,"GR-37002 -GR-37003 -GR-37005 -EL-37002 -EL-37003 -EL-37005",EUR,0.16,standard,Northern Sporades (Greek islands) special VAT rate. -2010-07-01,2016-06-01,"GR-64004 -EL-64004",EUR,0.16,standard,Thasos (Greek island) special VAT rate. -2010-07-01,2016-06-01,"GR-68002 -EL-68002",EUR,0.16,standard,Samothrace (Greek island) special VAT rate. -2010-07-01,,"GR-69 -EL-69",EUR,0,standard,Mount Athos (Greek self-governed part) is exempted of VAT. -2010-07-01,2016-06-01,"GR-81 -EL-81",EUR,0.16,standard,Dodecanese (Greek department) special VAT rate. -2010-07-01,2016-06-01,"GR-82 -EL-82",EUR,0.16,standard,Cyclades (Greek department) special VAT rate. -2010-07-01,2016-06-01,"GR-83 -EL-83",EUR,0.16,standard,Lesbos (Greek department) special VAT rate. -2010-07-01,2016-06-01,"GR-84 -EL-84",EUR,0.16,standard,Samos (Greek department) special VAT rate. -2010-07-01,2016-06-01,"GR-85 -EL-85",EUR,0.16,standard,Chios (Greek department) special VAT rate. -2011-01-04,,GS,GBP,0,standard,South Georgia and the South Sandwich Islands (British overseas territory) is exempted of VAT. -2012-03-01,,HR,HRK,0.25,standard,Croatia (member state) standard VAT rate. -2009-08-01,2012-03-01,HR,HRK,0.23,standard, -1998-08-01,2009-08-01,HR,HRK,0.22,standard, -2012-01-01,,HU,HUF,0.27,standard,Hungary (member state) standard VAT rate. -2009-07-01,2012-01-01,HU,HUF,0.25,standard, -2006-01-01,2009-07-01,HU,HUF,0.2,standard, -1988-01-01,2006-01-01,HU,HUF,0.25,standard, -2012-01-01,,IE,EUR,0.23,standard,Republic of Ireland (member state) standard VAT rate. -2010-01-01,2012-01-01,IE,EUR,0.21,standard, -2008-12-01,2010-01-01,IE,EUR,0.215,standard, -2002-03-01,2008-12-01,IE,EUR,0.21,standard, -2001-01-01,2002-03-01,IE,EUR,0.2,standard, -1991-03-01,2001-01-01,IE,EUR,0.21,standard, -1990-03-01,1991-03-01,IE,EUR,0.23,standard, -1986-03-01,1990-03-01,IE,EUR,0.25,standard, -1983-05-01,1986-03-01,IE,EUR,0.23,standard, -1983-03-01,1983-05-01,IE,EUR,0.35,standard, -1982-05-01,1983-03-01,IE,EUR,0.3,standard, -1980-05-01,1982-05-01,IE,EUR,0.25,standard, -1976-03-01,1980-05-01,IE,EUR,0.2,standard, -1973-09-03,1976-03-01,IE,EUR,0.195,standard, -1972-11-01,1973-09-03,IE,EUR,0.1637,standard, -2011-01-04,,IO,GBP,0,standard,British Indian Ocean Territory (British overseas territory) is exempted of VAT. -2013-10-01,,IT,EUR,0.22,standard,Italy (member state) standard VAT rate. -2011-09-17,2013-10-01,IT,EUR,0.21,standard, -1997-10-01,2011-09-17,IT,EUR,0.2,standard, -1988-08-01,1997-10-01,IT,EUR,0.19,standard, -1982-08-05,1988-08-01,IT,EUR,0.18,standard, -1981-01-01,1982-08-05,IT,EUR,0.15,standard, -1980-11-01,1981-01-01,IT,EUR,0.14,standard, -1980-07-03,1980-11-01,IT,EUR,0.15,standard, -1977-02-08,1980-07-03,IT,EUR,0.14,standard, -1973-01-01,1977-02-08,IT,EUR,0.12,standard, -2013-10-01,,"IT-22060 -CH-6911",CHF,0,standard,Campione (Italian town) is exempted of VAT. -2013-10-01,,IT-23030,EUR,0,standard,Livigno (Italian town) is exempted of VAT. -2011-01-04,,JE,GBP,0,standard,Jersey (British Crown dependency) is exempted of VAT. -2011-01-04,,KY,KYD,0,standard,Cayman Islands (British overseas territory) is exempted of VAT. -2009-09-01,,LT,EUR,0.21,standard,Lithuania (member state) standard VAT rate. -2009-01-01,2009-09-01,LT,EUR,0.19,standard, -1994-05-01,2009-01-01,LT,EUR,0.18,standard, -2015-01-01,,LU,EUR,0.17,standard,Luxembourg (member state) standard VAT rate. -1992-01-01,2015-01-01,LU,EUR,0.15,standard, -1983-07-01,1992-01-01,LU,EUR,0.12,standard, -1971-01-01,1983-07-01,LU,EUR,0.1,standard, -1970-01-01,1971-01-01,LU,EUR,0.8,standard, -2012-07-01,,LV,EUR,0.21,standard,Latvia (member state) standard VAT rate. -2011-01-01,2012-07-01,LV,EUR,0.22,standard, -2009-01-01,2011-01-01,LV,EUR,0.21,standard, -1995-05-01,2009-01-01,LV,EUR,0.18,standard, -2011-01-04,,MS,XCD,0,standard,Montserrat (British overseas territory) is exempted of VAT. -2004-01-01,,MT,EUR,0.18,standard,Malta (member state) standard VAT rate. -1995-01-01,2004-01-01,MT,EUR,0.15,standard, -2012-10-01,,NL,EUR,0.21,standard,Netherlands (member state) standard VAT rate. -2001-01-01,2012-10-01,NL,EUR,0.19,standard, -1992-10-01,2001-01-01,NL,EUR,0.175,standard, -1989-01-01,1992-10-01,NL,EUR,0.185,standard, -1986-10-01,1989-01-01,NL,EUR,0.2,standard, -1984-01-01,1986-10-01,NL,EUR,0.19,standard, -1976-01-01,1984-01-01,NL,EUR,0.18,standard, -1973-01-01,1976-01-01,NL,EUR,0.16,standard, -1971-01-01,1973-01-01,NL,EUR,0.14,standard, -1969-01-01,1971-01-01,NL,EUR,0.12,standard, -2012-10-01,,"NL-AW -AW",AWG,0,standard,Aruba (Dutch country) are exempted of VAT. -2012-10-01,,"NL-CW -NL-SX -CW -SX",ANG,0,standard,Curacao and Sint Maarten (Dutch countries) are exempted of VAT. -2012-10-01,,"NL-BQ1 -NL-BQ2 -NL-BQ3 -BQ -BQ-BO -BQ-SA -BQ-SE",USD,0,standard,"Bonaire, Saba and Sint Eustatius (Dutch special municipalities) are exempted of VAT." -2011-01-01,,PL,PLN,0.23,standard,Poland (member state) standard VAT rate. -1993-01-08,2011-01-01,PL,PLN,0.22,standard, -2011-01-04,,PN,NZD,0,standard,Pitcairn Islands (British overseas territory) is exempted of VAT. -2011-01-01,,PT,EUR,0.23,standard,Portugal (member state) standard VAT rate. -2010-07-01,2011-01-01,PT,EUR,0.21,standard, -2008-07-01,2010-07-01,PT,EUR,0.2,standard, -2005-07-01,2008-07-01,PT,EUR,0.21,standard, -2002-06-05,2005-07-01,PT,EUR,0.19,standard, -1995-01-01,2002-06-05,PT,EUR,0.17,standard, -1992-03-24,1995-01-01,PT,EUR,0.16,standard, -1988-02-01,1992-03-24,PT,EUR,0.17,standard, -1986-01-01,1988-02-01,PT,EUR,0.16,standard, -2011-01-01,,PT-20,EUR,0.18,standard,Azores (Portuguese autonomous region) special VAT rate. -2011-01-01,,PT-30,EUR,0.22,standard,Madeira (Portuguese autonomous region) special VAT rate. -2017-01-01,,RO,RON,0.19,standard,Romania (member state) standard VAT rate. -2016-01-01,2017-01-01,RO,RON,0.2,standard,Romania (member state) standard VAT rate. -2010-07-01,2016-01-01,RO,RON,0.24,standard, -2000-01-01,2010-07-01,RO,RON,0.19,standard, -1998-02-01,2000-01-01,RO,RON,0.22,standard, -1993-07-01,1998-02-01,RO,RON,0.18,standard, -1990-07-01,,SE,SEK,0.25,standard,Sweden (member state) standard VAT rate. -1983-01-01,1990-07-01,SE,SEK,0.2346,standard, -1981-11-16,1983-01-01,SE,SEK,0.2151,standard, -1980-09-08,1981-11-16,SE,SEK,0.2346,standard, -1977-06-01,1980-09-08,SE,SEK,0.2063,standard, -1971-01-01,1977-06-01,SE,SEK,0.1765,standard, -1969-01-01,1971-01-01,SE,SEK,0.1111,standard, -2011-01-04,,"AC -SH -SH-AC -SH-HL",SHP,0,standard,Ascension and Saint Helena (British overseas territory) is exempted of VAT. -2011-01-04,,"TA -SH-TA",GBP,0,standard,Tristan da Cunha (British oversea territory) is exempted of VAT. -2013-07-01,,SI,EUR,0.22,standard,Slovenia (member state) standard VAT rate. -2002-01-01,2013-07-01,SI,EUR,0.2,standard, -1999-07-01,2002-01-01,SI,EUR,0.19,standard, -2011-01-01,,SK,EUR,0.2,standard,Slovakia (member state) standard VAT rate. -2004-01-01,2011-01-01,SK,EUR,0.19,standard, -2003-01-01,2004-01-01,SK,EUR,0.2,standard, -1996-01-01,2003-01-01,SK,EUR,0.23,standard, -1993-08-01,1996-01-01,SK,EUR,0.25,standard, -1993-01-01,1993-08-01,SK,EUR,0.23,standard, -2011-01-04,,TC,USD,0,standard,Turks and Caicos Islands (British overseas territory) is exempted of VAT. -2011-01-04,,"GB -UK -IM",GBP,0.2,standard,"United Kingdom (member state) standard VAT rate. -Isle of Man (British self-governing dependency) is member of the EU VAT area and subjected to UK's standard VAT rate." -2010-01-01,2011-01-04,"GB -UK -IM",GBP,0.175,standard, -2008-12-01,2010-01-01,"GB -UK -IM",GBP,0.15,standard, -1991-04-01,2008-12-01,"GB -UK -IM",GBP,0.175,standard, -1979-06-18,1991-04-01,"GB -UK -IM",GBP,0.15,standard, -1974-07-29,1979-06-18,"GB -UK -IM",GBP,0.08,standard, -1973-04-01,1974-07-29,"GB -UK -IM",GBP,0.1,standard, -2011-01-04,,VG,USD,0,standard,British Virgin Islands (British overseas territory) is exempted of VAT. -2014-01-01,,CP,EUR,0,standard,Clipperton Island (French overseas possession) is exempted of VAT. -2019-11-15,,CH,CHF,0.077,standard,Switzerland standard VAT (added manually) -2019-11-15,,MC,EUR,0.196,standard,Monaco standard VAT (added manually) -2019-11-15,,FR,EUR,0.2,standard,France standard VAT (added manually) -2019-11-15,,GR,EUR,0.24,standard,Greece standard VAT (added manually) -2019-11-15,,GB,EUR,0.2,standard,UK standard VAT (added manually)