Compare commits
45 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49ef761b2e | ||
|
|
f82ed81b33 | ||
|
|
1ff577ddcd | ||
|
|
15ef20dbc1 | ||
|
|
dc507396eb | ||
|
|
aec2002a9f | ||
|
|
7dd57fb116 | ||
|
|
530e47586e | ||
|
|
e726f953a4 | ||
|
|
5697e313df | ||
|
|
1e57eb5fae | ||
|
|
a423dd9f49 | ||
|
|
6eef592cd8 | ||
|
|
93527fdc02 | ||
|
|
b790676940 | ||
|
|
435cfa46a6 | ||
|
|
e493a9f3d1 | ||
|
|
3bf2654b50 | ||
|
|
f0b604c6dc | ||
|
|
a33a344b40 | ||
|
|
871cccc2ae | ||
|
|
89418ca008 | ||
|
|
f6feb88708 | ||
|
|
5954093999 | ||
|
|
069556d9b6 | ||
|
|
f5372ecd1e | ||
|
|
3599f0bff4 | ||
|
|
efe411933f | ||
|
|
940eaf3a07 | ||
|
|
d399fe6e79 | ||
|
|
582e952187 | ||
|
|
76c2b9d16c | ||
|
|
44a20a5029 | ||
|
|
e0b2a0b6e2 | ||
|
|
7040d908dd | ||
|
|
b3dd57f189 | ||
|
|
7038a36b4d | ||
|
|
c56d6bd627 | ||
|
|
2d916936d6 | ||
|
|
270a03e7c5 | ||
|
|
4174c6226f | ||
|
|
7aec4dd938 | ||
|
|
6faa8b82e8 | ||
|
|
c29193f6c8 | ||
|
|
72741f2188 |
19 changed files with 652 additions and 155 deletions
20
Changelog
20
Changelog
|
|
@ -1,3 +1,23 @@
|
||||||
|
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
|
2.6.6: 2019-11-04
|
||||||
* feature: [admin] Add dumpuser management command that dumps a user's data in json (MR!716)
|
* feature: [admin] Add dumpuser management command that dumps a user's data in json (MR!716)
|
||||||
2.6.5: 2019-09-24
|
2.6.5: 2019-09-24
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-07-03 11:18+0000\n"
|
"POT-Creation-Date: 2019-11-15 17:33+0000\n"
|
||||||
"PO-Revision-Date: 2018-03-30 23:22+0000\n"
|
"PO-Revision-Date: 2018-03-30 23:22+0000\n"
|
||||||
"Last-Translator: b'Anonymous User <coder.purple+25@gmail.com>'\n"
|
"Last-Translator: b'Anonymous User <coder.purple+25@gmail.com>'\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|
@ -20,7 +20,7 @@ msgstr ""
|
||||||
"X-Translated-Using: django-rosetta 0.8.1\n"
|
"X-Translated-Using: django-rosetta 0.8.1\n"
|
||||||
|
|
||||||
msgid "CMS Favicon"
|
msgid "CMS Favicon"
|
||||||
msgstr ""
|
msgstr "CMS Favicon"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Your New VM %(vm_name)s at Data Center Light"
|
msgid "Your New VM %(vm_name)s at Data Center Light"
|
||||||
|
|
@ -52,7 +52,7 @@ msgid "Login"
|
||||||
msgstr "Anmelden"
|
msgstr "Anmelden"
|
||||||
|
|
||||||
msgid "Dashboard"
|
msgid "Dashboard"
|
||||||
msgstr ""
|
msgstr "Dashboard"
|
||||||
|
|
||||||
msgid "Thank you for contacting us."
|
msgid "Thank you for contacting us."
|
||||||
msgstr "Nachricht gesendet."
|
msgstr "Nachricht gesendet."
|
||||||
|
|
@ -64,7 +64,7 @@ msgid "Get in touch with us!"
|
||||||
msgstr "Sende uns eine Nachricht."
|
msgstr "Sende uns eine Nachricht."
|
||||||
|
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr "Name"
|
||||||
|
|
||||||
msgid "Please enter your name."
|
msgid "Please enter your name."
|
||||||
msgstr "Bitte gib Deinen Namen ein."
|
msgstr "Bitte gib Deinen Namen ein."
|
||||||
|
|
@ -108,7 +108,7 @@ msgid "Your account details are as follows"
|
||||||
msgstr "Deine Account Details sind unten aufgelistet"
|
msgstr "Deine Account Details sind unten aufgelistet"
|
||||||
|
|
||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr "Username"
|
msgstr "Benusername"
|
||||||
|
|
||||||
msgid "Your email address"
|
msgid "Your email address"
|
||||||
msgstr "Deine E-Mail-Adresse"
|
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."
|
msgstr "Bitte gib einen Wert von %(min_ram)s bis 200 ein."
|
||||||
|
|
||||||
msgid "VM hosting"
|
msgid "VM hosting"
|
||||||
msgstr ""
|
msgstr "VM Hosting"
|
||||||
|
|
||||||
msgid "month"
|
msgid "month"
|
||||||
msgstr "Monat"
|
msgstr "Monat"
|
||||||
|
|
@ -207,14 +207,14 @@ msgstr ""
|
||||||
|
|
||||||
msgid "Only wants you to pay for what you actually need."
|
msgid "Only wants you to pay for what you actually need."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Möchte, dass du nur bezahlst, was du auch wirklich brauchst: Wähle deine "
|
"Du möchtest nur das bezahlen, was du auch wirklich brauchst: Wähle deine "
|
||||||
"Ressourcen individuell aus!
"
|
"Ressourcen individuell aus!
"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Is creative, using a modern and alternative design for a data center in "
|
"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."
|
"order to make it more sustainable and affordable at the same time."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Ist kreativ, indem es sich ein modernes und alternatives Layout zu Nutze "
|
"Es ist kreativ, da es sich ein modernes und alternatives Layout zu Nutze"
|
||||||
"macht um Nachhaltigkeit zu fördern und somit erschwingliche Preise bieten zu "
|
"macht um Nachhaltigkeit zu fördern und somit erschwingliche Preise bieten zu "
|
||||||
"können.
"
|
"können.
"
|
||||||
|
|
||||||
|
|
@ -222,9 +222,9 @@ msgid ""
|
||||||
"Cuts down the costs for you by using FOSS (Free Open Source Software) "
|
"Cuts down the costs for you by using FOSS (Free Open Source Software) "
|
||||||
"exclusively, wherefore we can save money from paying licenses."
|
"exclusively, wherefore we can save money from paying licenses."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Sorgt dafür, dass unnötige Kosten erspart werden, indem es ausschliesslich "
|
"Um unnötige Kosten zu sparen werden, wird ausschliesslich Software auf"
|
||||||
"mit FOSS (Free Open Source Software) arbeitet und wir daher auf "
|
"Basis von FOSS (Free Open Source Software) eingesetzt und dadurch können auf "
|
||||||
"Lizenzgebühren verzichten können.
"
|
"Lizenzgebühren verzichtet werden.
"
|
||||||
|
|
||||||
msgid "Scale out"
|
msgid "Scale out"
|
||||||
msgstr "Skalierung"
|
msgstr "Skalierung"
|
||||||
|
|
@ -311,7 +311,7 @@ msgid "Billing Address"
|
||||||
msgstr "Rechnungsadresse"
|
msgstr "Rechnungsadresse"
|
||||||
|
|
||||||
msgid "Make a payment"
|
msgid "Make a payment"
|
||||||
msgstr ""
|
msgstr "Tätige eine Bezahlung"
|
||||||
|
|
||||||
msgid "Your Order"
|
msgid "Your Order"
|
||||||
msgstr "Deine Bestellung"
|
msgstr "Deine Bestellung"
|
||||||
|
|
@ -375,6 +375,9 @@ msgstr "Letzten"
|
||||||
msgid "Type"
|
msgid "Type"
|
||||||
msgstr "Typ"
|
msgstr "Typ"
|
||||||
|
|
||||||
|
msgid "Expiry"
|
||||||
|
msgstr "Ablaufdatum"
|
||||||
|
|
||||||
msgid "SELECT"
|
msgid "SELECT"
|
||||||
msgstr "AUSWÄHLEN"
|
msgstr "AUSWÄHLEN"
|
||||||
|
|
||||||
|
|
@ -415,14 +418,23 @@ msgstr "Bestellungsübersicht"
|
||||||
msgid "Product"
|
msgid "Product"
|
||||||
msgstr "Produkt"
|
msgstr "Produkt"
|
||||||
|
|
||||||
|
msgid "Price"
|
||||||
|
msgstr "Preise"
|
||||||
|
|
||||||
|
msgid "VAT for"
|
||||||
|
msgstr "MwSt für"
|
||||||
|
|
||||||
|
msgid "Total Amount"
|
||||||
|
msgstr "Gesamtsumme"
|
||||||
|
|
||||||
msgid "Amount"
|
msgid "Amount"
|
||||||
msgstr ""
|
msgstr "Betrag"
|
||||||
|
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr ""
|
msgstr "Beschreibung"
|
||||||
|
|
||||||
msgid "Recurring"
|
msgid "Recurring"
|
||||||
msgstr ""
|
msgstr "Wiederholend"
|
||||||
|
|
||||||
msgid "Subtotal"
|
msgid "Subtotal"
|
||||||
msgstr "Zwischensumme"
|
msgstr "Zwischensumme"
|
||||||
|
|
@ -434,12 +446,20 @@ msgstr "Mehrwertsteuer"
|
||||||
#| msgid ""
|
#| msgid ""
|
||||||
#| "By clicking \"Place order\" this plan will charge your credit card "
|
#| "By clicking \"Place order\" this plan will charge your credit card "
|
||||||
#| "account with %(total_price)s CHF/month"
|
#| "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 ""
|
msgid ""
|
||||||
"By clicking \"Place order\" this plan will charge your credit card account "
|
"By clicking \"Place order\" this plan will charge your credit card account "
|
||||||
"with %(total_price)s CHF/month"
|
"with %(total_price)s CHF/month"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit "
|
"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit %(total_price)s "
|
||||||
"%(vm_total_price)s CHF pro Monat belastet"
|
"CHF pro Monat belastet"
|
||||||
|
|
||||||
#, fuzzy, python-format
|
#, fuzzy, python-format
|
||||||
#| msgid ""
|
#| msgid ""
|
||||||
|
|
@ -470,10 +490,10 @@ msgid "Hold tight, we are processing your request"
|
||||||
msgstr "Bitte warten - wir verarbeiten Deine Anfrage gerade"
|
msgstr "Bitte warten - wir verarbeiten Deine Anfrage gerade"
|
||||||
|
|
||||||
msgid "OK"
|
msgid "OK"
|
||||||
msgstr ""
|
msgstr "Ok"
|
||||||
|
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr "Schliessen"
|
||||||
|
|
||||||
msgid "Some problem encountered. Please try again later."
|
msgid "Some problem encountered. Please try again later."
|
||||||
msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal."
|
msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal."
|
||||||
|
|
@ -485,7 +505,7 @@ msgid "Tech Stack"
|
||||||
msgstr "Tech Stack"
|
msgstr "Tech Stack"
|
||||||
|
|
||||||
msgid "We are seriously open source."
|
msgid "We are seriously open source."
|
||||||
msgstr "Wir sind vollends opensource."
|
msgstr "Wir sind vollends Open Source."
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
" Our full software stack is open source – We don't use anything that isn't "
|
" Our full software stack is open source – We don't use anything that isn't "
|
||||||
|
|
@ -555,13 +575,13 @@ msgid "Starting from only 15CHF per month. Try now."
|
||||||
msgstr "Unser Angebot beginnt bei 15 CHF pro Monat. Probier's jetzt aus!"
|
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."
|
msgid "Actions speak louder than words. Let's do it, try our VM now."
|
||||||
msgstr "Tagen sagen mehr als Worte – Teste jetzt unsere VM!"
|
msgstr "Taten sagen mehr als Worte – Teste jetzt unsere VM!"
|
||||||
|
|
||||||
msgid "Invalid number of cores"
|
msgid "Invalid number of cores"
|
||||||
msgstr "Ungültige Anzahle CPU-Kerne"
|
msgstr "Ungültige Anzahle CPU-Kerne"
|
||||||
|
|
||||||
msgid "Invalid calculator properties"
|
msgid "Invalid calculator properties"
|
||||||
msgstr ""
|
msgstr "Ungültige Berechnungseigenschaften"
|
||||||
|
|
||||||
msgid "Invalid RAM size"
|
msgid "Invalid RAM size"
|
||||||
msgstr "Ungültige RAM-Grösse"
|
msgstr "Ungültige RAM-Grösse"
|
||||||
|
|
@ -571,7 +591,7 @@ msgstr "Ungültige Speicher-Grösse"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Incorrect pricing name. Please contact support{support_email}"
|
msgid "Incorrect pricing name. Please contact support{support_email}"
|
||||||
msgstr ""
|
msgstr "Ungültige Preisbezeichnung. Bitte kontaktiere den Support{support_email}"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{user} does not have permission to access the card"
|
msgid "{user} does not have permission to access the card"
|
||||||
|
|
@ -598,11 +618,14 @@ msgid "An error occurred while associating the card. Details: {details}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Beim Verbinden der Karte ist ein Fehler aufgetreten. Details: {details}"
|
"Beim Verbinden der Karte ist ein Fehler aufgetreten. Details: {details}"
|
||||||
|
|
||||||
msgid "Confirmation of your payment"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid " This is a monthly recurring plan."
|
msgid " This is a monthly recurring plan."
|
||||||
msgstr ""
|
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"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
|
|
@ -613,7 +636,8 @@ msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"Cheers,\n"
|
"Cheers,\n"
|
||||||
"Your Data Center Light team"
|
"Your Data Center Light team"
|
||||||
msgstr ""
|
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"
|
||||||
|
|
||||||
msgid "Thank you for the payment."
|
msgid "Thank you for the payment."
|
||||||
msgstr "Danke für Deine Bestellung."
|
msgstr "Danke für Deine Bestellung."
|
||||||
|
|
@ -621,7 +645,7 @@ msgstr "Danke für Deine Bestellung."
|
||||||
msgid ""
|
msgid ""
|
||||||
"You will soon receive a confirmation email of the payment. You can always "
|
"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."
|
"contact us at info@ungleich.ch for any question that you may have."
|
||||||
msgstr ""
|
msgstr "Du wirst bald eine Bestätigungs-E-Mail über die Zahlung erhalten. Du kannst jederzeit unter info@ungleich.ch kontaktieren."
|
||||||
|
|
||||||
msgid "Thank you for the order."
|
msgid "Thank you for the order."
|
||||||
msgstr "Danke für Deine Bestellung."
|
msgstr "Danke für Deine Bestellung."
|
||||||
|
|
@ -644,9 +668,6 @@ msgstr ""
|
||||||
#~ msgid "Card Number"
|
#~ msgid "Card Number"
|
||||||
#~ msgstr "Kreditkartennummer"
|
#~ msgstr "Kreditkartennummer"
|
||||||
|
|
||||||
#~ msgid "Expiry Date"
|
|
||||||
#~ msgstr "Ablaufdatum"
|
|
||||||
|
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "You are not making any payment yet. After placing your order, you will be "
|
#~ "You are not making any payment yet. After placing your order, you will be "
|
||||||
#~ "taken to the Submit Payment Page."
|
#~ "taken to the Submit Payment Page."
|
||||||
|
|
@ -655,9 +676,6 @@ msgstr ""
|
||||||
#~ "ausgelöst, nachdem Du die Bestellung auf der nächsten Seite bestätigt "
|
#~ "ausgelöst, nachdem Du die Bestellung auf der nächsten Seite bestätigt "
|
||||||
#~ "hast."
|
#~ "hast."
|
||||||
|
|
||||||
#~ msgid "Pricing"
|
|
||||||
#~ msgstr "Preise"
|
|
||||||
|
|
||||||
#~ msgid "Order VM"
|
#~ msgid "Order VM"
|
||||||
#~ msgstr "VM bestellen"
|
#~ msgstr "VM bestellen"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
import logging
|
import logging
|
||||||
import oca
|
|
||||||
import sys
|
import sys
|
||||||
import stripe
|
import uuid
|
||||||
|
|
||||||
|
import oca
|
||||||
|
import stripe
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from membership.models import CustomUser, DeletedUser
|
|
||||||
from hosting.models import (
|
from hosting.models import (
|
||||||
HostingOrder, HostingBill, VMDetail, UserCardDetail, UserHostingKey
|
UserCardDetail, UserHostingKey
|
||||||
)
|
)
|
||||||
|
from membership.models import CustomUser, DeletedUser
|
||||||
from opennebula_api.models import OpenNebulaManager
|
from opennebula_api.models import OpenNebulaManager
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -79,75 +82,6 @@ class Command(BaseCommand):
|
||||||
else:
|
else:
|
||||||
logger.error("Error while deleting the StripeCustomer")
|
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
|
# delete UserCardDetail
|
||||||
ucds = UserCardDetail.objects.filter(
|
ucds = UserCardDetail.objects.filter(
|
||||||
stripe_customer=stripe_customer
|
stripe_customer=stripe_customer
|
||||||
|
|
@ -179,8 +113,10 @@ class Command(BaseCommand):
|
||||||
user_id = cus_user.id
|
user_id = cus_user.id
|
||||||
)
|
)
|
||||||
|
|
||||||
# delete CustomUser
|
# reset CustomUser
|
||||||
cus_user.delete()
|
cus_user.email = str(uuid.uuid4())
|
||||||
|
cus_user.validated = 0
|
||||||
|
cus_user.save()
|
||||||
|
|
||||||
# remove user from OpenNebula
|
# remove user from OpenNebula
|
||||||
manager = OpenNebulaManager()
|
manager = OpenNebulaManager()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from pprint import pprint
|
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from membership.models import CustomUser
|
from membership.models import CustomUser
|
||||||
|
|
@ -19,7 +19,6 @@ class Command(BaseCommand):
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
try:
|
try:
|
||||||
for email in options['customer_email']:
|
for email in options['customer_email']:
|
||||||
logger.debug("Creating dump for the user {}".format(email))
|
|
||||||
try:
|
try:
|
||||||
cus_user = CustomUser.objects.get(email=email)
|
cus_user = CustomUser.objects.get(email=email)
|
||||||
except CustomUser.DoesNotExist as dne:
|
except CustomUser.DoesNotExist as dne:
|
||||||
|
|
@ -38,7 +37,7 @@ class Command(BaseCommand):
|
||||||
vm_ids.append(order.vm_id)
|
vm_ids.append(order.vm_id)
|
||||||
order_dict["VM_ID"] = order.vm_id
|
order_dict["VM_ID"] = order.vm_id
|
||||||
order_dict["Order Nr."] = order.id
|
order_dict["Order Nr."] = order.id
|
||||||
order_dict["Created On"] = str(order.created_on)
|
order_dict["Created On"] = str(order.created_at)
|
||||||
order_dict["Price"] = order.price
|
order_dict["Price"] = order.price
|
||||||
order_dict["Payment card details"] = {
|
order_dict["Payment card details"] = {
|
||||||
"last4": order.last4,
|
"last4": order.last4,
|
||||||
|
|
@ -82,7 +81,7 @@ class Command(BaseCommand):
|
||||||
"IPv6": vm_detail.ipv6,
|
"IPv6": vm_detail.ipv6,
|
||||||
"OS": vm_detail.configuration,
|
"OS": vm_detail.configuration,
|
||||||
}
|
}
|
||||||
order_dict["Terminated on"] = vm_detail.terminated_at
|
order_dict["Terminated on"] = str(vm_detail.terminated_at)
|
||||||
|
|
||||||
orders_dict[order.vm_id] = order_dict
|
orders_dict[order.vm_id] = order_dict
|
||||||
|
|
||||||
|
|
@ -116,10 +115,9 @@ class Command(BaseCommand):
|
||||||
"Name": uhk.name,
|
"Name": uhk.name,
|
||||||
"Created on": str(uhk.created_at)
|
"Created on": str(uhk.created_at)
|
||||||
}
|
}
|
||||||
if uhk.private_key is not None:
|
if uhk.private_key:
|
||||||
key["Private key"] = uhk.private_key
|
key["Private key"] = uhk.private_key
|
||||||
keys[uhk.name] = key
|
keys[uhk.name] = key
|
||||||
print("User {} dump is follows:")
|
|
||||||
output_dict = {
|
output_dict = {
|
||||||
"User details": {
|
"User details": {
|
||||||
"Name": cus_user.name,
|
"Name": cus_user.name,
|
||||||
|
|
@ -131,7 +129,6 @@ class Command(BaseCommand):
|
||||||
"Payment cards": cards,
|
"Payment cards": cards,
|
||||||
"SSH Keys": keys
|
"SSH Keys": keys
|
||||||
}
|
}
|
||||||
pprint(output_dict)
|
print(json.dumps(output_dict, indent=4))
|
||||||
logger.debug("Dumped user {} SUCCESSFULLY.".format(email))
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(" *** Error occurred. Details {}".format(str(e)))
|
print(" *** Error occurred. Details {}".format(str(e)))
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,25 @@
|
||||||
</p>
|
</p>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
|
{% if generic_payment_details.vat_rate > 0 %}
|
||||||
|
<p>
|
||||||
|
<span>{% trans "Price" %}: </span>
|
||||||
|
<strong class="pull-right">CHF {{generic_payment_details.amount_before_vat|floatformat:2|intcomma}}</strong>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>{% trans "VAT for" %} {{generic_payment_details.vat_country}} ({{generic_payment_details.vat_rate}}%) : </span>
|
||||||
|
<strong class="pull-right">CHF {{generic_payment_details.vat_amount|floatformat:2|intcomma}}</strong>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>{% trans "Total Amount" %} : </span>
|
||||||
|
<strong class="pull-right">CHF {{generic_payment_details.amount|floatformat:2|intcomma}}</strong>
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
<p>
|
<p>
|
||||||
<span>{% trans "Amount" %}: </span>
|
<span>{% trans "Amount" %}: </span>
|
||||||
<strong class="pull-right">CHF {{generic_payment_details.amount|floatformat:2|intcomma}}</strong>
|
<strong class="pull-right">CHF {{generic_payment_details.amount|floatformat:2|intcomma}}</strong>
|
||||||
</p>
|
</p>
|
||||||
|
{% endif %}
|
||||||
{% if generic_payment_details.description %}
|
{% if generic_payment_details.description %}
|
||||||
<p>
|
<p>
|
||||||
<span>{% trans "Description" %}: </span>
|
<span>{% trans "Description" %}: </span>
|
||||||
|
|
@ -139,7 +154,11 @@
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% if generic_payment_details %}
|
{% if generic_payment_details %}
|
||||||
{% if generic_payment_details.recurring %}
|
{% if generic_payment_details.recurring %}
|
||||||
<div class="dcl-place-order-text">{% 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 %}.</div>
|
{% if generic_payment_details.recurring_interval == 'year' %}
|
||||||
|
<div class="dcl-place-order-text">{% 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 %}.</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="dcl-place-order-text">{% 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 %}.</div>
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="dcl-place-order-text">{% 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 %}.</div>
|
<div class="dcl-place-order-text">{% 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 %}.</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,9 @@ from utils.forms import (
|
||||||
BillingAddressForm, BillingAddressFormSignup, UserBillingAddressForm,
|
BillingAddressForm, BillingAddressFormSignup, UserBillingAddressForm,
|
||||||
BillingAddress
|
BillingAddress
|
||||||
)
|
)
|
||||||
from utils.hosting_utils import get_vm_price_with_vat, get_all_public_keys
|
from utils.hosting_utils import (
|
||||||
|
get_vm_price_with_vat, get_all_public_keys, get_vat_rate_for_country
|
||||||
|
)
|
||||||
from utils.stripe_utils import StripeUtils
|
from utils.stripe_utils import StripeUtils
|
||||||
from utils.tasks import send_plain_email_task
|
from utils.tasks import send_plain_email_task
|
||||||
from .cms_models import DCLCalculatorPluginModel
|
from .cms_models import DCLCalculatorPluginModel
|
||||||
|
|
@ -412,10 +414,21 @@ class PaymentOrderView(FormView):
|
||||||
product = generic_payment_form.cleaned_data.get(
|
product = generic_payment_form.cleaned_data.get(
|
||||||
'product_name'
|
'product_name'
|
||||||
)
|
)
|
||||||
|
user_country_vat_rate = get_vat_rate_for_country(
|
||||||
|
address_form.cleaned_data["country"]
|
||||||
|
)
|
||||||
gp_details = {
|
gp_details = {
|
||||||
"product_name": product.product_name,
|
"product_name": product.product_name,
|
||||||
"amount": generic_payment_form.cleaned_data.get(
|
"vat_rate": user_country_vat_rate * 100,
|
||||||
'amount'
|
"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"])
|
||||||
),
|
),
|
||||||
"recurring": generic_payment_form.cleaned_data.get(
|
"recurring": generic_payment_form.cleaned_data.get(
|
||||||
'recurring'
|
'recurring'
|
||||||
|
|
@ -424,7 +437,9 @@ class PaymentOrderView(FormView):
|
||||||
'description'
|
'description'
|
||||||
),
|
),
|
||||||
"product_id": product.id,
|
"product_id": product.id,
|
||||||
"product_slug": product.product_slug
|
"product_slug": product.product_slug,
|
||||||
|
"recurring_interval":
|
||||||
|
product.product_subscription_interval
|
||||||
}
|
}
|
||||||
request.session["generic_payment_details"] = (
|
request.session["generic_payment_details"] = (
|
||||||
gp_details
|
gp_details
|
||||||
|
|
@ -743,6 +758,7 @@ class OrderConfirmationView(DetailView, FormView):
|
||||||
|
|
||||||
if ('generic_payment_type' not in request.session or
|
if ('generic_payment_type' not in request.session or
|
||||||
(request.session['generic_payment_details']['recurring'])):
|
(request.session['generic_payment_details']['recurring'])):
|
||||||
|
recurring_interval = 'month'
|
||||||
if 'generic_payment_details' in request.session:
|
if 'generic_payment_details' in request.session:
|
||||||
amount_to_be_charged = (
|
amount_to_be_charged = (
|
||||||
round(
|
round(
|
||||||
|
|
@ -755,6 +771,10 @@ class OrderConfirmationView(DetailView, FormView):
|
||||||
amount_to_be_charged
|
amount_to_be_charged
|
||||||
)
|
)
|
||||||
stripe_plan_id = plan_name
|
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:
|
else:
|
||||||
template = request.session.get('template')
|
template = request.session.get('template')
|
||||||
specs = request.session.get('specs')
|
specs = request.session.get('specs')
|
||||||
|
|
@ -781,7 +801,9 @@ class OrderConfirmationView(DetailView, FormView):
|
||||||
stripe_plan = stripe_utils.get_or_create_stripe_plan(
|
stripe_plan = stripe_utils.get_or_create_stripe_plan(
|
||||||
amount=amount_to_be_charged,
|
amount=amount_to_be_charged,
|
||||||
name=plan_name,
|
name=plan_name,
|
||||||
stripe_plan_id=stripe_plan_id)
|
stripe_plan_id=stripe_plan_id,
|
||||||
|
interval=recurring_interval
|
||||||
|
)
|
||||||
subscription_result = stripe_utils.subscribe_customer_to_plan(
|
subscription_result = stripe_utils.subscribe_customer_to_plan(
|
||||||
stripe_api_cus_id,
|
stripe_api_cus_id,
|
||||||
[{"plan": stripe_plan.get(
|
[{"plan": stripe_plan.get(
|
||||||
|
|
@ -972,6 +994,9 @@ class OrderConfirmationView(DetailView, FormView):
|
||||||
'reply_to': [context['email']],
|
'reply_to': [context['email']],
|
||||||
}
|
}
|
||||||
send_plain_email_task.delay(email_data)
|
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 = {
|
email_data = {
|
||||||
'subject': _("Confirmation of your payment"),
|
'subject': _("Confirmation of your payment"),
|
||||||
|
|
@ -985,7 +1010,7 @@ class OrderConfirmationView(DetailView, FormView):
|
||||||
name=user.get('name'),
|
name=user.get('name'),
|
||||||
amount=gp_details['amount'],
|
amount=gp_details['amount'],
|
||||||
recurring=(
|
recurring=(
|
||||||
_(' This is a monthly recurring plan.')
|
recurring_text
|
||||||
if gp_details['recurring'] else ''
|
if gp_details['recurring'] else ''
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -109,9 +109,14 @@ class ProductPaymentForm(GenericPaymentForm):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if self.product.product_is_subscription:
|
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(
|
self.fields['amount'].label = "{amt} ({payment_type})".format(
|
||||||
amt=_('Amount in CHF'),
|
amt=_('Amount in CHF'),
|
||||||
payment_type=_('Monthly subscription')
|
payment_type=payment_type
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.fields['amount'].label = "{amt} ({payment_type})".format(
|
self.fields['amount'].label = "{amt} ({payment_type})".format(
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-09-15 03:39+0000\n"
|
"POT-Creation-Date: 2019-11-15 16:40+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|
@ -28,28 +28,31 @@ msgid "User does not exist"
|
||||||
msgstr "Der Benutzer existiert nicht"
|
msgstr "Der Benutzer existiert nicht"
|
||||||
|
|
||||||
msgid "Choose a product"
|
msgid "Choose a product"
|
||||||
msgstr ""
|
msgstr "Wähle ein Produkt"
|
||||||
|
|
||||||
msgid "Amount in CHF"
|
msgid "Amount in CHF"
|
||||||
msgstr "Betrag"
|
msgstr "Betrag"
|
||||||
|
|
||||||
msgid "Recurring monthly"
|
msgid "Recurring monthly"
|
||||||
msgstr ""
|
msgstr "monatlich wiederkehrend"
|
||||||
|
|
||||||
msgid "Amount field does not match"
|
msgid "Amount field does not match"
|
||||||
msgstr ""
|
msgstr "Betragsfeld stimmt nicht überein"
|
||||||
|
|
||||||
msgid "Recurring field does not match"
|
msgid "Recurring field does not match"
|
||||||
msgstr ""
|
msgstr "Betragsfeld stimmt nicht überein"
|
||||||
|
|
||||||
msgid "Product name"
|
msgid "Product name"
|
||||||
msgstr "Produkt"
|
msgstr "Produkt"
|
||||||
|
|
||||||
msgid "Monthly subscription"
|
msgid "Monthly subscription"
|
||||||
msgstr ""
|
msgstr "Monatliches Abonnement"
|
||||||
|
|
||||||
|
msgid "Yearly subscription"
|
||||||
|
msgstr "Jährliches Abonnement"
|
||||||
|
|
||||||
msgid "One time payment"
|
msgid "One time payment"
|
||||||
msgstr ""
|
msgstr "Einmalzahlung"
|
||||||
|
|
||||||
msgid "Confirm Password"
|
msgid "Confirm Password"
|
||||||
msgstr "Passwort Bestätigung"
|
msgstr "Passwort Bestätigung"
|
||||||
|
|
@ -73,7 +76,7 @@ msgid "Please input a proper SSH key"
|
||||||
msgstr "Bitte verwende einen gültigen SSH-Key"
|
msgstr "Bitte verwende einen gültigen SSH-Key"
|
||||||
|
|
||||||
msgid "Comma not accepted in the name of the key"
|
msgid "Comma not accepted in the name of the key"
|
||||||
msgstr ""
|
msgstr "Komma im Namen des Keys wird nicht akzeptiert"
|
||||||
|
|
||||||
msgid "All Rights Reserved"
|
msgid "All Rights Reserved"
|
||||||
msgstr "Alle Rechte vorbehalten"
|
msgstr "Alle Rechte vorbehalten"
|
||||||
|
|
@ -239,7 +242,8 @@ msgid "You can view your VM detail by clicking the button below."
|
||||||
msgstr "Um die Rechnung zu sehen, klicke auf den Button unten."
|
msgstr "Um die Rechnung zu sehen, klicke auf den Button unten."
|
||||||
|
|
||||||
msgid "You can log in to your VM by the username <strong>puffy</strong>."
|
msgid "You can log in to your VM by the username <strong>puffy</strong>."
|
||||||
msgstr "Du kannst Dich auf Deiner VM mit dem user <strong>puffy</strong> einloggen."
|
msgstr ""
|
||||||
|
"Du kannst Dich auf Deiner VM mit dem user <strong>puffy</strong> einloggen."
|
||||||
|
|
||||||
msgid "View Detail"
|
msgid "View Detail"
|
||||||
msgstr "Details anzeigen"
|
msgstr "Details anzeigen"
|
||||||
|
|
@ -400,13 +404,19 @@ msgid "Amount"
|
||||||
msgstr "Betrag"
|
msgstr "Betrag"
|
||||||
|
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr ""
|
msgstr "Beschreibung"
|
||||||
|
|
||||||
msgid "Recurring"
|
msgid "Recurring"
|
||||||
msgstr ""
|
msgstr "wiederkehrend"
|
||||||
|
|
||||||
|
msgid "of"
|
||||||
|
msgstr "von"
|
||||||
|
|
||||||
|
msgid "each year"
|
||||||
|
msgstr "jedes Jahr"
|
||||||
|
|
||||||
msgid "of every month"
|
msgid "of every month"
|
||||||
msgstr ""
|
msgstr "jeden Monat"
|
||||||
|
|
||||||
msgid "BACK TO LIST"
|
msgid "BACK TO LIST"
|
||||||
msgstr "ZURÜCK ZUR LISTE"
|
msgstr "ZURÜCK ZUR LISTE"
|
||||||
|
|
@ -418,16 +428,13 @@ msgid "VM ID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "IP Address"
|
msgid "IP Address"
|
||||||
msgstr ""
|
msgstr "IP-Adresse"
|
||||||
|
|
||||||
msgid "See Invoice"
|
msgid "See Invoice"
|
||||||
msgstr "Siehe Rechnung"
|
msgstr "Siehe Rechnung"
|
||||||
|
|
||||||
msgid "Page"
|
msgid "Page"
|
||||||
msgstr ""
|
msgstr "Seite"
|
||||||
|
|
||||||
msgid "of"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Anmelden"
|
msgstr "Anmelden"
|
||||||
|
|
@ -489,7 +496,7 @@ msgid "Hold tight, we are processing your request"
|
||||||
msgstr "Bitte warten - wir bearbeiten Deine Anfrage gerade"
|
msgstr "Bitte warten - wir bearbeiten Deine Anfrage gerade"
|
||||||
|
|
||||||
msgid "OK"
|
msgid "OK"
|
||||||
msgstr ""
|
msgstr "Ok"
|
||||||
|
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Schliessen"
|
msgstr "Schliessen"
|
||||||
|
|
@ -845,7 +852,7 @@ msgstr "Ungültige Speicher-Grösse"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Incorrect pricing name. Please contact support{support_email}"
|
msgid "Incorrect pricing name. Please contact support{support_email}"
|
||||||
msgstr ""
|
msgstr "Ungültige Preisbezeichnung. Bitte kontaktiere den Support{support_email}"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"We could not find the requested VM. Please "
|
"We could not find the requested VM. Please "
|
||||||
|
|
@ -864,7 +871,7 @@ msgstr "Fehler beenden VM"
|
||||||
msgid ""
|
msgid ""
|
||||||
"VM terminate action timed out. Please contact support@datacenterlight.ch for "
|
"VM terminate action timed out. Please contact support@datacenterlight.ch for "
|
||||||
"further information."
|
"further information."
|
||||||
msgstr ""
|
msgstr "VM beendet wegen Zeitüberschreitung. Bitte kontaktiere support@datacenterlight.ch für weitere Informationen."
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Virtual Machine %(vm_name)s Cancelled"
|
msgid "Virtual Machine %(vm_name)s Cancelled"
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,12 @@ class Command(BaseCommand):
|
||||||
logger.debug("Invoice %s exists already. Not importing." % invoice['invoice_id'])
|
logger.debug("Invoice %s exists already. Not importing." % invoice['invoice_id'])
|
||||||
except MonthlyHostingBill.DoesNotExist as dne:
|
except MonthlyHostingBill.DoesNotExist as dne:
|
||||||
logger.debug("Invoice id %s does not exist" % invoice['invoice_id'])
|
logger.debug("Invoice id %s does not exist" % invoice['invoice_id'])
|
||||||
num_invoice_created += 1 if MonthlyHostingBill.create(invoice) is not None else logger.error("Did not import invoice for %s" % str(invoice))
|
|
||||||
|
if MonthlyHostingBill.create(invoice) is not None:
|
||||||
|
num_invoice_created += 1
|
||||||
|
else:
|
||||||
|
logger.error("Did not import invoice for %s"
|
||||||
|
"" % str(invoice))
|
||||||
self.stdout.write(
|
self.stdout.write(
|
||||||
self.style.SUCCESS("Number of invoices imported = %s" % num_invoice_created)
|
self.style.SUCCESS("Number of invoices imported = %s" % num_invoice_created)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
44
hosting/management/commands/import_vat_rates.py
Normal file
44
hosting/management/commands/import_vat_rates.py
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
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)))
|
||||||
30
hosting/migrations/0057_vatrates.py
Normal file
30
hosting/migrations/0057_vatrates.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- 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),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- 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),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import decimal
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
@ -78,13 +79,17 @@ class GenericProduct(AssignPermissionsMixin, models.Model):
|
||||||
product_price = models.DecimalField(max_digits=6, decimal_places=2)
|
product_price = models.DecimalField(max_digits=6, decimal_places=2)
|
||||||
product_vat = models.DecimalField(max_digits=6, decimal_places=4, default=0)
|
product_vat = models.DecimalField(max_digits=6, decimal_places=4, default=0)
|
||||||
product_is_subscription = models.BooleanField(default=True)
|
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):
|
def __str__(self):
|
||||||
return self.product_name
|
return self.product_name
|
||||||
|
|
||||||
def get_actual_price(self):
|
def get_actual_price(self, vat_rate=None):
|
||||||
|
VAT = vat_rate if vat_rate is not None else self.product_vat
|
||||||
return round(
|
return round(
|
||||||
self.product_price + (self.product_price * self.product_vat), 2
|
float(self.product_price) + float(self.product_price) * float(VAT), 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -319,7 +324,10 @@ class MonthlyHostingBill(AssignPermissionsMixin, models.Model):
|
||||||
logger.debug("Neither subscription id nor vm_id available")
|
logger.debug("Neither subscription id nor vm_id available")
|
||||||
logger.debug("Can't import invoice")
|
logger.debug("Can't import invoice")
|
||||||
return None
|
return None
|
||||||
|
if args['order'] is None:
|
||||||
|
logger.error(
|
||||||
|
"Order is None for {}".format(args['invoice_id']))
|
||||||
|
return None
|
||||||
instance = cls.objects.create(
|
instance = cls.objects.create(
|
||||||
created=datetime.utcfromtimestamp(
|
created=datetime.utcfromtimestamp(
|
||||||
args['created']).replace(tzinfo=pytz.utc),
|
args['created']).replace(tzinfo=pytz.utc),
|
||||||
|
|
@ -704,3 +712,13 @@ class UserCardDetail(AssignPermissionsMixin, models.Model):
|
||||||
return ucd
|
return ucd
|
||||||
except UserCardDetail.DoesNotExist:
|
except UserCardDetail.DoesNotExist:
|
||||||
return None
|
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='')
|
||||||
|
|
@ -195,8 +195,13 @@
|
||||||
{% if invoice.order.subscription_id %}
|
{% if invoice.order.subscription_id %}
|
||||||
<p>
|
<p>
|
||||||
<span>{% trans "Recurring" %}: </span>
|
<span>{% trans "Recurring" %}: </span>
|
||||||
<strong class="pull-right">{{invoice.order.created_at|date:'d'|ordinal}}
|
{% if invoice.order.generic_product.product_subscription_interval == 'year' %}
|
||||||
|
<strong class="pull-right">{{invoice.order.created_at|date:'d'|ordinal}} {% trans "of" %} {{invoice.order.created_at|date:'b'|title}}
|
||||||
|
{% trans "each year" %}</strong>
|
||||||
|
{% else %}
|
||||||
|
<strong class="pull-right">{{invoice.order.created_at|date:'d'|ordinal}}
|
||||||
{% trans "of every month" %}</strong>
|
{% trans "of every month" %}</strong>
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,13 @@
|
||||||
{% if order.subscription_id %}
|
{% if order.subscription_id %}
|
||||||
<p>
|
<p>
|
||||||
<span>{% trans "Recurring" %}: </span>
|
<span>{% trans "Recurring" %}: </span>
|
||||||
<strong class="pull-right">{{order.created_at|date:'d'|ordinal}} {% trans "of every month" %}</strong>
|
{% if order.generic_product.product_subscription_interval == 'year' %}
|
||||||
|
<strong class="pull-right">{{order.created_at|date:'d'|ordinal}} {% trans "of" %} {{order.created_at|date:'b'|title}}
|
||||||
|
{% trans "each year" %}</strong>
|
||||||
|
{% else %}
|
||||||
|
<strong class="pull-right">{{order.created_at|date:'d'|ordinal}}
|
||||||
|
{% trans "of every month" %}</strong>
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1268,6 +1268,10 @@ class InvoiceDetailView(LoginRequiredMixin, DetailView):
|
||||||
context['vm']['total_price'] = (
|
context['vm']['total_price'] = (
|
||||||
price + vat - discount['amount']
|
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:
|
except WrongIdError:
|
||||||
logger.error("WrongIdError while accessing "
|
logger.error("WrongIdError while accessing "
|
||||||
"invoice {}".format(obj.invoice_id))
|
"invoice {}".format(obj.invoice_id))
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import subprocess
|
||||||
from oca.pool import WrongIdError
|
from oca.pool import WrongIdError
|
||||||
|
|
||||||
from datacenterlight.models import VMPricing
|
from datacenterlight.models import VMPricing
|
||||||
from hosting.models import UserHostingKey, VMDetail
|
from hosting.models import UserHostingKey, VMDetail, VATRates
|
||||||
from opennebula_api.serializers import VirtualMachineSerializer
|
from opennebula_api.serializers import VirtualMachineSerializer
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -150,6 +150,20 @@ def ping_ok(host_ipv6):
|
||||||
return True
|
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:
|
class HostingUtils:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def clear_items_from_list(from_list, items_list):
|
def clear_items_from_list(from_list, items_list):
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,8 @@ class StripeUtils(object):
|
||||||
return charge
|
return charge
|
||||||
|
|
||||||
@handleStripeError
|
@handleStripeError
|
||||||
def get_or_create_stripe_plan(self, amount, name, stripe_plan_id):
|
def get_or_create_stripe_plan(self, amount, name, stripe_plan_id,
|
||||||
|
interval=""):
|
||||||
"""
|
"""
|
||||||
This function checks if a StripePlan with the given
|
This function checks if a StripePlan with the given
|
||||||
stripe_plan_id already exists. If it exists then the function
|
stripe_plan_id already exists. If it exists then the function
|
||||||
|
|
@ -238,6 +239,10 @@ class StripeUtils(object):
|
||||||
:param stripe_plan_id: The id of the Stripe plan to be
|
:param stripe_plan_id: The id of the Stripe plan to be
|
||||||
created. Use get_stripe_plan_id_string function to
|
created. Use get_stripe_plan_id_string function to
|
||||||
obtain the name of the plan to be created
|
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
|
:return: The StripePlan object if it exists else creates a
|
||||||
Plan object in Stripe and a local StripePlan and
|
Plan object in Stripe and a local StripePlan and
|
||||||
returns it. Returns None in case of Stripe error
|
returns it. Returns None in case of Stripe error
|
||||||
|
|
@ -245,6 +250,7 @@ class StripeUtils(object):
|
||||||
_amount = float(amount)
|
_amount = float(amount)
|
||||||
amount = int(_amount * 100) # stripe amount unit, in cents
|
amount = int(_amount * 100) # stripe amount unit, in cents
|
||||||
stripe_plan_db_obj = None
|
stripe_plan_db_obj = None
|
||||||
|
plan_interval = interval if interval is not "" else self.INTERVAL
|
||||||
try:
|
try:
|
||||||
stripe_plan_db_obj = StripePlan.objects.get(
|
stripe_plan_db_obj = StripePlan.objects.get(
|
||||||
stripe_plan_id=stripe_plan_id)
|
stripe_plan_id=stripe_plan_id)
|
||||||
|
|
@ -252,7 +258,7 @@ class StripeUtils(object):
|
||||||
try:
|
try:
|
||||||
self.stripe.Plan.create(
|
self.stripe.Plan.create(
|
||||||
amount=amount,
|
amount=amount,
|
||||||
interval=self.INTERVAL,
|
interval=plan_interval,
|
||||||
name=name,
|
name=name,
|
||||||
currency=self.CURRENCY,
|
currency=self.CURRENCY,
|
||||||
id=stripe_plan_id)
|
id=stripe_plan_id)
|
||||||
|
|
|
||||||
318
vat_rates.csv
Normal file
318
vat_rates.csv
Normal file
|
|
@ -0,0 +1,318 @@
|
||||||
|
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)
|
||||||
|
Loading…
Add table
Add a link
Reference in a new issue