uncloud-mravi/nextcloud/views.py

290 lines
13 KiB
Python

import logging
from django.views.generic.base import TemplateView
from stripe.error import CardError
from django.shortcuts import redirect, render
from django.contrib import messages
from django.utils.translation import get_language, ugettext_lazy as _
from django.contrib.auth.decorators import login_required
from django.views.decorators.cache import cache_control
from django.utils.decorators import method_decorator
from django.views import View
from django.views.generic import FormView, DetailView
from django.views.generic.list import ListView
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from .forms import InitialRequestForm, RequestDomainsNamesForm
from uncloud_pay.forms import BillingAddressForm
from django.urls import reverse
from django.conf import settings
from django.utils import timezone
from django_q.models import Schedule
from django_q.tasks import schedule
from django.http import (
HttpResponseRedirect, JsonResponse, HttpResponse
)
from rest_framework import viewsets, permissions
from uncloud_pay.models import PricingPlan
from uncloud_pay.utils import get_order_total_with_vat
from uncloud_pay.models import *
from uncloud_pay.utils import validate_vat_number
from uncloud_pay.selectors import get_billing_address_for_user, get_balance_for_user
import uncloud_pay.stripe as uncloud_stripe
from .models import VMMachine
from .serializers import *
from .utils import *
from ldap.ldapobject import LDAPObject
logger = logging.getLogger(__name__)
class PricingView(TemplateView):
template_name = "nextcloud/pricing.html"
class IndexView(FormView):
template_name = "nextcloud/index.html"
form_class = InitialRequestForm
success_url = "/nextcloud#requestform"
success_message = "Thank you, we will contact you as soon as possible"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['vm_pricing'] = PricingPlan.get_default_pricing()
return context
def form_valid(self, form):
self.request.session['order'] = form.cleaned_data
pricing = get_order_total_with_vat(
form.cleaned_data['cores'],
form.cleaned_data['memory'],
form.cleaned_data['storage'],
form.cleaned_data['pricing_name'],
False
)
self.request.session['pricing'] = pricing
return HttpResponseRedirect(reverse('nextcloud:payment'))
class OrderPaymentView(FormView):
template_name = 'nextcloud/order_details.html'
success_url = 'nextcloud:order_confirmation'
form_class = BillingAddressForm
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
def get_context_data(self, **kwargs):
context = super(OrderPaymentView, self).get_context_data(**kwargs)
default_pricing = PricingPlan.get_default_pricing()
if 'billing_address_data' in self.request.session:
billing_address_form = BillingAddressForm(
initial=self.request.session['billing_address_data']
)
else:
old_active = get_billing_address_for_user(self.request.user)
billing_address_form = BillingAddressForm(
instance=old_active
) if old_active else BillingAddressForm(
initial={'active': True, 'owner': self.request.user.id}
)
if self.request.GET.get('product', False):
matched_prod = Product.objects.filter(name=self.request.GET.get('product')).first()
if matched_prod:
self.request.session['order'] = matched_prod.config
details_form = InitialRequestForm(
initial=self.request.session.get('order', {'pricing_name': default_pricing.name})
)
balance = get_balance_for_user(self.request.user)
customer_id = uncloud_stripe.get_customer_id_for(self.request.user)
#TODO optimize this part for better performance
uncloud_stripe.sync_cards_for_user(self.request.user)
cards = uncloud_stripe.get_customer_cards(customer_id)
pricing = self.request.session.get('pricing', {'name': default_pricing.name, 'total': 0})
context.update({
'vm_pricing': PricingPlan.get_by_name(pricing['name']),
'billing_address_form': billing_address_form,
'details_form': details_form,
'balance': balance,
'cards': cards,
'stripe_key': settings.STRIPE_PUBLIC_KEY,
'show_cards': True if balance < pricing['total'] else False,
})
return context
@cache_control(no_cache=True, must_revalidate=True, no_store=True)
def get(self, request, *args, **kwargs):
for k in ['vat_validation_status', 'token', 'id_payment_method', 'total']:
if request.session.get(k):
request.session.pop(k)
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
details_form = InitialRequestForm(request.POST)
billing_address_form = BillingAddressForm(request.POST)
context = self.get_context_data()
if not details_form.is_valid() or not billing_address_form.is_valid():
context.update({'details_form': details_form,
'billing_address_form': billing_address_form})
return self.render_to_response(context)
address = get_billing_address_for_user(self.request.user)
if address:
form = BillingAddressForm(self.request.POST, instance=address)
else:
form = BillingAddressForm(self.request.POST)
if form.is_valid:
billing_address_ins = form.save()
self.request.session["billing_address_id"] = billing_address_ins.id
self.request.session['billing_address_data'] = billing_address_form.cleaned_data
self.request.session['billing_address_data']['owner'] = self.request.user.id
id_payment_method = self.request.POST.get('id_payment_method', False)
selected_card = False
if id_payment_method and id_payment_method != 'undefined':
uncloud_stripe.attach_payment_method(id_payment_method, self.request.user)
selected_card = StripeCreditCard.objects.filter(card_id=id_payment_method).first()
selected_card.activate()
vat_number = billing_address_form.cleaned_data.get('vat_number').strip()
if vat_number:
customer_id = uncloud_stripe.get_customer_id_for(self.request.user)
validate_result = validate_vat_number(
stripe_customer_id=customer_id,
billing_address_id=billing_address_ins.id
)
if 'error' in validate_result and validate_result['error']:
messages.add_message(
self.request, messages.ERROR, validate_result["error"],
extra_tags='error'
)
return HttpResponseRedirect(
reverse('nextcloud:payment')
)
self.request.session["vat_validation_status"] = validate_result["status"]
specs = details_form.cleaned_data
vat_rate = VATRate.get_vat_rate(billing_address_ins)
vat_validation_status = "verified" if billing_address_ins.vat_number_validated_on and billing_address_ins.vat_number_verified else False
pricing = get_order_total_with_vat(
specs['cores'], specs['memory'], specs['storage'], context['vm_pricing'].name,
vat_rate=vat_rate * 100, vat_validation_status = vat_validation_status
)
self.request.session['pricing'] = pricing
self.request.session['order'] = specs
self.request.session['vat_validation_status'] = vat_validation_status
amount = get_balance_for_user(self.request.user) - pricing["total"]
if (amount < 0 and not selected_card):
messages.add_message(
self.request, messages.ERROR, "You haven't enough balance please select credit card to continue",
extra_tags='error'
)
return HttpResponseRedirect(
reverse('nextcloud:payment')
)
return HttpResponseRedirect(reverse('nextcloud:order_confirmation'))
class OrderConfirmationView(DetailView):
template_name = "nextcloud/order_confirmation.html"
context_object_name = "order"
model = Order
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
def get_context_data(self, **kwargs):
context = {
'order': self.request.session.get('order'),
'pricing': self.request.session.get('pricing'),
'balance': get_balance_for_user(self.request.user)
}
return context
@cache_control(no_cache=True, must_revalidate=True, no_store=True)
def get(self, request, *args, **kwargs):
context = self.get_context_data()
context['domains_form'] = RequestDomainsNamesForm(initial={})
if ('order' not in request.session):
return HttpResponseRedirect(reverse('nextcloud:index'))
elif 'pricing' not in self.request.session or 'vat_validation_status' not in self.request.session:
return HttpResponseRedirect(reverse('nextcloud:payment'))
total = self.request.session['pricing']['total']
amount = get_balance_for_user(self.request.user) - total
if (amount < 0):
context['stripe_deposit_amount'] = max(amount, settings.MIN_PER_TRANSACTION)
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
domains_form = RequestDomainsNamesForm(self.request.POST)
if domains_form.is_valid():
customer = StripeCustomer.objects.get(owner=self.request.user)
billing_address = BillingAddress.objects.get(id=request.session.get('billing_address_id'))
total = self.request.session['pricing']['total']
self.request.session['order']['domain'] = domains_form.cleaned_data.get('subdomain') + "." + domains_form.cleaned_data.get('main_domain')
try:
amount = get_balance_for_user(self.request.user) - total
if (amount < 0):
Payment.deposit(request.user, max(abs(amount), settings.MIN_PER_TRANSACTION), source='stripe')
amount = get_balance_for_user(self.request.user) - total
if (amount < 0):
messages.add_message(
self.request, messages.ERROR, "Please make sure that you have enough balance in your wallet and try again later.",
extra_tags='error'
)
return HttpResponseRedirect(
reverse('nextcloud:order_confirmation')
)
order, bill = finalize_order(request, customer,
billing_address,
total,
PricingPlan.get_by_name(self.request.session['pricing']['name']),
request.session.get('order'))
if order and bill:
self.request.session['bill_id'] = bill.id
return HttpResponseRedirect(reverse('uncloud_pay:order_success'))
except CardError as e:
messages.add_message(
self.request, messages.ERROR, e.user_message,
extra_tags='error'
)
return HttpResponseRedirect(
reverse('nextcloud:order_confirmation')
)
context = self.get_context_data()
context['domains_form'] = domains_form
return self.render_to_response(context)
class OrdersView(ListView):
template_name = "nextcloud/orders.html"
model = Order
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
def get_queryset(self):
return Order.objects.filter(owner=self.request.user).order_by('-creation_date')
def post(self, request, *args, **kwargs):
order = Order.objects.get(id=request.POST.get('order_id', 0))
order.cancel()
if hasattr(order, 'instance_id'):
last_bill_record = BillRecord.objects.filter(order=order).order_by('id').last()
schedule('nextcloud.tasks.delete_instance',
order.instance_id,
schedule_type=Schedule.ONCE,
next_run=last_bill_record.ending_date or (timezone.now() + datetime.timedelta(hours=1)))
return JsonResponse({'message': 'Successfully Cancelled'})
class InstancesView(ListView):
template_name = "nextcloud/instances.html"
model = VMMachine
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
def get_queryset(self):
return VMMachine.objects.filter(owner=self.request.user).order_by('-creation_date')