forked from uncloud/uncloud
Test Full cycle and fix some issues
This commit is contained in:
parent
1aeb757e22
commit
2e05ebbf67
19 changed files with 131 additions and 98 deletions
|
@ -11,7 +11,7 @@ from django.conf import settings
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
|
||||||
from uncloud_pay.models import Order
|
from uncloud_pay.models import Order, BillRecord
|
||||||
|
|
||||||
|
|
||||||
# Initialize logger.
|
# Initialize logger.
|
||||||
|
@ -71,6 +71,24 @@ class VMInstance(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.id}-{self.order}"
|
return f"{self.id}-{self.order}"
|
||||||
|
|
||||||
def delete_for_bill(self, bill):
|
@classmethod
|
||||||
#TODO delete related instances
|
def delete_for_bill(cls, bill):
|
||||||
|
bill_records = BillRecord.objects.filter(bill=bill)
|
||||||
|
for record in bill_records:
|
||||||
|
instances = VMInstance.objects.filter(order=record.order)
|
||||||
|
for instance in instances:
|
||||||
|
instance.delete()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_instance(cls, order):
|
||||||
|
machine = cls.objects.filter(order=order).first()
|
||||||
|
if not machine:
|
||||||
|
order_config = json.loads(order.config)
|
||||||
|
isOpenRegistration = order_config.get('is_open_registration', False)
|
||||||
|
instance_config = {'cpuCores': order_config['cores'], 'ram': order_config['memory'], 'storage': order_config['storage'],
|
||||||
|
'matrixDomain': order_config['matrix_domain'], 'homeserverDomain': order_config['homeserver_domain'],
|
||||||
|
'webClientDomain': order_config['webclient_domain'], 'isOpenRegistration': isOpenRegistration}
|
||||||
|
cls.objects.create(owner=order.owner, order=order, vm_name=order_config['homeserver_domain'],
|
||||||
|
homeserver_domain=order_config['homeserver_domain'],webclient_domain=order_config['webclient_domain'],
|
||||||
|
config=instance_config)
|
|
@ -1,19 +1,2 @@
|
||||||
import json
|
|
||||||
from matrixhosting.models import VMInstance
|
|
||||||
from uncloud_pay.models import Order
|
|
||||||
from django.db.models.signals import post_save
|
|
||||||
from django.dispatch import receiver
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Order)
|
|
||||||
def create_instance(sender, instance, created, **kwargs):
|
|
||||||
if not created:
|
|
||||||
return
|
|
||||||
machine = VMInstance.objects.filter(order=instance).first()
|
|
||||||
if not machine:
|
|
||||||
order_config = json.loads(instance.config)
|
|
||||||
instance_config = {'cpuCores': order_config['cores'], 'ram': order_config['memory'], 'storage': order_config['storage'],
|
|
||||||
'matrixDomain': order_config['matrix_domain'], 'homeserverDomain': order_config['homeserver_domain'],
|
|
||||||
'webClientDomain': order_config['webclient_domain'], 'isOpenRegistration': order_config['is_open_registration']}
|
|
||||||
VMInstance.objects.create(owner=instance.owner, order=instance, vm_name=order_config['homeserver_domain'],
|
|
||||||
homeserver_domain=order_config['homeserver_domain'],webclient_domain=order_config['webclient_domain'],
|
|
||||||
config=instance_config)
|
|
||||||
|
|
|
@ -44,7 +44,35 @@
|
||||||
|
|
||||||
<div id="main-wrapper">
|
<div id="main-wrapper">
|
||||||
{% block navbar %} {% include "matrixhosting/includes/_navbar.html" with transparent_header=transparent_header %} {%endblock %}
|
{% block navbar %} {% include "matrixhosting/includes/_navbar.html" with transparent_header=transparent_header %} {%endblock %}
|
||||||
|
{% block main %}
|
||||||
|
<div class="container">
|
||||||
|
<!-- Steps Progress bar -->
|
||||||
|
{% if messages %}
|
||||||
|
<div class="row">
|
||||||
|
{% for message in messages %}
|
||||||
|
{% if 'error' in message.tags %}
|
||||||
|
<div class="col-lg-12 alert alert-danger" role="alert">
|
||||||
|
<h4 class="alert-heading">{%trans "Error!" %}</h4>
|
||||||
|
<p class="mb-0">
|
||||||
|
{{ message|safe }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="col-lg-12 alert alert-success" role="alert">
|
||||||
|
<p class="mb-0 float-left">
|
||||||
|
{{ message|safe }}
|
||||||
|
</p>
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% block content %} {% endblock %}
|
{% block content %} {% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
{% include "matrixhosting/includes/_footer.html" %}
|
{% include "matrixhosting/includes/_footer.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
{% block title %} Bills {% endblock %}
|
{% block title %} Bills {% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
|
||||||
<div class="bg-white shadow-md rounded p-4 my-4">
|
<div class="bg-white shadow-md rounded p-4 my-4">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
|
@ -182,7 +181,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block js_extra %}
|
{% block js_extra %}
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
{% block title %} Payment Methods {% endblock %}
|
{% block title %} Payment Methods {% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
|
||||||
<div class="bg-white shadow-md rounded p-4 my-4">
|
<div class="bg-white shadow-md rounded p-4 my-4">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
|
@ -128,7 +127,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block js_extra %}
|
{% block js_extra %}
|
||||||
<script src="https://js.stripe.com/v3/"></script>
|
<script src="https://js.stripe.com/v3/"></script>
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
============================== -->
|
============================== -->
|
||||||
{% url 'matrix:index' as index_url %}
|
{% url 'matrix:index' as index_url %}
|
||||||
{% url 'matrix:orders' as orders_url %}
|
{% url 'matrix:orders' as orders_url %}
|
||||||
|
{% url 'matrix:instances' as instances_url %}
|
||||||
{% url 'matrix:billing' as payments_url %}
|
{% url 'matrix:billing' as payments_url %}
|
||||||
<nav class="primary-menu navbar navbar-expand-lg">
|
<nav class="primary-menu navbar navbar-expand-lg">
|
||||||
<div id="header-nav" class="collapse navbar-collapse">
|
<div id="header-nav" class="collapse navbar-collapse">
|
||||||
|
@ -27,8 +28,9 @@
|
||||||
<li><a href="">Pricing</a></li>
|
<li><a href="">Pricing</a></li>
|
||||||
<li><a href="">Contact Us</a></li>
|
<li><a href="">Contact Us</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li><a class="{% if request.path == orders_url %}active{%endif%}" href="{{orders_url}}">Orders</a></li>
|
<li class="{% if orders_url in request.path %}active{%endif%}"><a href="{{orders_url}}">Orders</a></li>
|
||||||
<li class="{% if request.path == payments_url %}active{%endif%}"><a href="{{payments_url}}">{%trans "Billing" %}</a></li>
|
<li class="{% if instances_url in request.path %}active{%endif%}"><a href="{{instances_url}}">Instances</a></li>
|
||||||
|
<li class="{% if payments_url in request.path %}active{%endif%}"><a href="{{payments_url}}">{%trans "Billing" %}</a></li>
|
||||||
<li><a href="">Help</a></li>
|
<li><a href="">Help</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block main %}
|
||||||
<!-- Content
|
<!-- Content
|
||||||
============================================= -->
|
============================================= -->
|
||||||
<div id="content">
|
<div id="content">
|
||||||
|
|
|
@ -7,18 +7,26 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Content -->
|
<!-- Page Content -->
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="container">
|
|
||||||
<div class="row p-1 mt-4">
|
<div class="row p-1 mt-4">
|
||||||
<div class="col-lg-12 bg-white shadow-sm border border-light rounded py-4 mb-4">
|
<div class="col-lg-12 bg-white shadow-sm border border-light rounded py-4 mb-4">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-6">
|
||||||
<h3 class="text-5 font-weight-400 d-flex align-items-center px-1 mb-4">{% trans "Instances"%}</h3>
|
<h3 class="text-5 font-weight-400 d-flex align-items-center px-1 mb-4">{% trans "Instances"%}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-sm-6">
|
||||||
|
<div class="float-right">
|
||||||
|
<a class="border border-primary rounded p-2" href="{% url 'matrix:payment' %}">{% trans "Request New Instance"%}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Title
|
<!-- Title
|
||||||
=============================== -->
|
=============================== -->
|
||||||
<div class="transaction-title py-2 px-1">
|
<div class="transaction-title py-2 px-1">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-1 col-sm-1 text-center"><span class="">{% trans "ID"%}</span></div>
|
<div class="col-1 col-sm-1 text-center"><span class="">{% trans "ID"%}</span></div>
|
||||||
<div class="col-2 col-sm-2 text-center"><span class="">{% trans "Creation Date"%}</span></div>
|
<div class="col-2 col-sm-2 text-center"><span class="">{% trans "Creation Date"%}</span></div>
|
||||||
<div class="col-3 col-sm-3 d-none d-sm-block text-center">{% trans "Homeserver Domain"%}</div>
|
<div class="col-3 col-sm-3 text-center">{% trans "Homeserver Domain"%}</div>
|
||||||
<div class="col-3 col-sm-3 text-right">{% trans "WebClient Domain"%}</div>
|
<div class="col-3 col-sm-3 text-center">{% trans "WebClient Domain"%}</div>
|
||||||
<div class="col-1 col-sm-1 text-center"><span class="">{% trans "Order"%}</span></div>
|
<div class="col-1 col-sm-1 text-center"><span class="">{% trans "Order"%}</span></div>
|
||||||
<div class="col-2 col-sm-2 text-center">{% trans "Termination Date"%}</div>
|
<div class="col-2 col-sm-2 text-center">{% trans "Termination Date"%}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,10 +41,10 @@
|
||||||
<div class="row align-items-center flex-row">
|
<div class="row align-items-center flex-row">
|
||||||
<div class="col-1 col-sm-1 text-center"> <span class="d-block text-3 font-weight-400">#{{instance.id}}</span></div>
|
<div class="col-1 col-sm-1 text-center"> <span class="d-block text-3 font-weight-400">#{{instance.id}}</span></div>
|
||||||
<div class="col-2 col-sm-2 text-center"> <span class="d-block text-2 font-weight-300">{{instance.creation_date|date:"Y-m-d"}}</span></div>
|
<div class="col-2 col-sm-2 text-center"> <span class="d-block text-2 font-weight-300">{{instance.creation_date|date:"Y-m-d"}}</span></div>
|
||||||
<div class="col-3 col-sm-3 d-none d-sm-block text-right text-1"> <span>{{instance.homeserver_domain}}</span> </div>
|
<div class="col-3 col-sm-3 text-center text-1"> <span>{{instance.homeserver_domain}}</span> </div>
|
||||||
<div class="col-3 col-sm-3 d-none d-sm-block text-right text-1"> <span>{{instance.webclient_domain}}</span> </div>
|
<div class="col-3 col-sm-3 text-center text-1"> <span>{{instance.webclient_domain}}</span> </div>
|
||||||
<div class="col-1 col-sm-1 text-center text-2"><span class="">#{{instance.order.id}}</span></div>
|
<div class="col-1 col-sm-1 text-center text-2"><span class="">#{{instance.order.id}}</span></div>
|
||||||
<div class="col-2 col-sm-2 d-none d-sm-block text-center text-2"> <span class=" text-uppercase">{{order.termination_date|date:"Y-m-d"}}</span> </div>
|
<div class="col-2 col-sm-2 text-center text-2"> <span class=" text-uppercase">{{order.termination_date|date:"Y-m-d"}}</span> </div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
|
@ -45,8 +53,6 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js_extra %}
|
{% block js_extra %}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
{% block title %} Request Details {% endblock %}
|
{% block title %} Request Details {% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
|
||||||
<!-- Steps Progress bar -->
|
<!-- Steps Progress bar -->
|
||||||
<div class="row mt-3 mb-4">
|
<div class="row mt-3 mb-4">
|
||||||
<div class="col-lg-12 mx-auto mb-4">
|
<div class="col-lg-12 mx-auto mb-4">
|
||||||
|
@ -15,7 +14,7 @@
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<div class="progress-bar"></div>
|
<div class="progress-bar"></div>
|
||||||
</div>
|
</div>
|
||||||
<a href="#" class="step-dot"></a> </div>
|
<a href="{% url 'matrix:payment' %}" class="step-dot"></a> </div>
|
||||||
<div class="col-4 step active">
|
<div class="col-4 step active">
|
||||||
<div class="step-name">{%trans "Confirm" %}</div>
|
<div class="step-name">{%trans "Confirm" %}</div>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
|
@ -199,7 +198,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js_extra %}
|
{% block js_extra %}
|
||||||
|
|
|
@ -5,31 +5,6 @@
|
||||||
{% block title %} Request Details {% endblock %}
|
{% block title %} Request Details {% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
|
||||||
<!-- Steps Progress bar -->
|
|
||||||
{% if messages %}
|
|
||||||
<div class="row">
|
|
||||||
{% for message in messages %}
|
|
||||||
{% if 'error' in message.tags %}
|
|
||||||
<div class="col-lg-12 alert alert-danger" role="alert">
|
|
||||||
<h4 class="alert-heading">{%trans "Error!" %}</h4>
|
|
||||||
<p class="mb-0">
|
|
||||||
{{ message|safe }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="col-lg-12 alert alert-success" role="alert">
|
|
||||||
<p class="mb-0 float-left">
|
|
||||||
{{ message|safe }}
|
|
||||||
</p>
|
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="row mt-3 mb-4">
|
<div class="row mt-3 mb-4">
|
||||||
<div class="col-lg-12 mx-auto mb-4">
|
<div class="col-lg-12 mx-auto mb-4">
|
||||||
<div class="row widget-steps">
|
<div class="row widget-steps">
|
||||||
|
@ -264,8 +239,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js_extra %}
|
{% block js_extra %}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
{% block title %} Request Details {% endblock %}
|
{% block title %} Request Details {% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
|
||||||
<div class="row mt-3 mb-4">
|
<div class="row mt-3 mb-4">
|
||||||
<div class="col-lg-12 mx-auto mb-4">
|
<div class="col-lg-12 mx-auto mb-4">
|
||||||
<div class="row widget-steps">
|
<div class="row widget-steps">
|
||||||
|
@ -41,9 +40,8 @@
|
||||||
<p class="text-success text-8 font-weight-500 line-height-07">{%trans "Success!" %}</p>
|
<p class="text-success text-8 font-weight-500 line-height-07">{%trans "Success!" %}</p>
|
||||||
<p class="lead">{%trans "Order has been successfully added. Your VM will be up and running in a few moments. " %}</p>
|
<p class="lead">{%trans "Order has been successfully added. Your VM will be up and running in a few moments. " %}</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-3 mb-4">{%trans "We will send you a confirmation email as soon as it is ready." %} {%trans "Go to your dashboard" %} <a class="btn-link" href="{% url 'matrix:billing' %}">{%trans "Billing" %}</a>.</p>
|
<p class="text-3 mb-4">{%trans "We will send you a confirmation email as soon as it is ready." %} {%trans "Go to your dashboard" %} <a class="btn-link" href="{% url 'matrixhosting:bills' %}">{%trans "Billing" %}</a>.</p>
|
||||||
<a href="{% url 'matrix:invoice_download' %}" class="btn btn-white border border-success text-success" role="button"><i class="fas fa-print"></i> {%trans "Download Invoice" %}</a>
|
<a href="{% url 'matrix:invoice_download' bill_id=bill_id %}" class="btn btn-white border border-success text-success" role="button"><i class="fas fa-print"></i> {%trans "Download Invoice" %}</a>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Content -->
|
<!-- Page Content -->
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="container">
|
|
||||||
<div class="row p-1 mt-4">
|
<div class="row p-1 mt-4">
|
||||||
<div class="col-lg-12 bg-white shadow-sm border border-light rounded py-4 mb-4">
|
<div class="col-lg-12 bg-white shadow-sm border border-light rounded py-4 mb-4">
|
||||||
<h3 class="text-5 font-weight-400 d-flex align-items-center px-1 mb-4">{% trans "Orders"%}</h3>
|
<h3 class="text-5 font-weight-400 d-flex align-items-center px-1 mb-4">{% trans "Orders"%}</h3>
|
||||||
|
@ -104,8 +103,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="alert" role="alert" id="result"></div>
|
<div class="alert" role="alert" id="result"></div>
|
||||||
<!-- /.banner -->
|
<!-- /.banner -->
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
{% block title %} Payments {% endblock %}
|
{% block title %} Payments {% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
|
||||||
<div class="bg-white shadow-md rounded p-4 my-4">
|
<div class="bg-white shadow-md rounded p-4 my-4">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
|
@ -116,7 +115,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js_extra %}
|
{% block js_extra %}
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.contrib.auth import get_user_model
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from .models import VMInstance
|
from .models import VMInstance
|
||||||
from uncloud_pay.models import Order, PricingPlan, BillingAddress, Product, RecurringPeriod
|
from uncloud_pay.models import Order, PricingPlan, BillingAddress, Product, RecurringPeriod, Bill, BillRecord
|
||||||
|
|
||||||
|
|
||||||
vm_product_config = {
|
vm_product_config = {
|
||||||
|
@ -54,6 +54,26 @@ class VMInstanceTestCase(TestCase):
|
||||||
self.product.recurring_periods.add(self.default_recurring_period,
|
self.product.recurring_periods.add(self.default_recurring_period,
|
||||||
through_defaults= { 'is_default': True })
|
through_defaults= { 'is_default': True })
|
||||||
|
|
||||||
|
def test_delete_matrix_vm_related_to_bill(self):
|
||||||
|
order = Order.objects.create(owner=self.user,
|
||||||
|
recurring_period=self.default_recurring_period,
|
||||||
|
billing_address=self.ba,
|
||||||
|
pricing_plan = self.pricing_plan,
|
||||||
|
product=self.product,
|
||||||
|
config=self.config)
|
||||||
|
VMInstance.create_instance(order)
|
||||||
|
instances = VMInstance.objects.filter(order=order)
|
||||||
|
self.assertEqual(len(instances), 1)
|
||||||
|
bill = Bill.create_next_bill_for_order(order, ending_date=order.next_cancel_or_downgrade_date(order.starting_date))
|
||||||
|
bill_records = BillRecord.objects.filter(bill=bill)
|
||||||
|
self.assertEqual(len(bill_records), 1)
|
||||||
|
self.assertEqual(bill_records[0].order, order)
|
||||||
|
|
||||||
|
VMInstance.delete_for_bill(bill)
|
||||||
|
instances = VMInstance.objects.filter(order=order)
|
||||||
|
self.assertEqual(len(instances), 0)
|
||||||
|
|
||||||
|
|
||||||
def test_create_matrix_vm(self):
|
def test_create_matrix_vm(self):
|
||||||
order = Order.objects.create(owner=self.user,
|
order = Order.objects.create(owner=self.user,
|
||||||
recurring_period=self.default_recurring_period,
|
recurring_period=self.default_recurring_period,
|
||||||
|
@ -61,6 +81,7 @@ class VMInstanceTestCase(TestCase):
|
||||||
pricing_plan = self.pricing_plan,
|
pricing_plan = self.pricing_plan,
|
||||||
product=self.product,
|
product=self.product,
|
||||||
config=self.config)
|
config=self.config)
|
||||||
|
VMInstance.create_instance(order)
|
||||||
instances = VMInstance.objects.filter(order=order)
|
instances = VMInstance.objects.filter(order=order)
|
||||||
self.assertEqual(len(instances), 1)
|
self.assertEqual(len(instances), 1)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import json
|
import json
|
||||||
from uncloud_pay.models import Product, Order, ProductToRecurringPeriod
|
from uncloud_pay.models import Product, Order, ProductToRecurringPeriod, Bill, Payment
|
||||||
|
from .models import VMInstance
|
||||||
|
|
||||||
|
|
||||||
def finalize_order(request, customer, billing_address,
|
def finalize_order(request, customer, billing_address,
|
||||||
|
@ -17,4 +18,12 @@ def finalize_order(request, customer, billing_address,
|
||||||
product = product,
|
product = product,
|
||||||
config=json.dumps(specs)
|
config=json.dumps(specs)
|
||||||
)
|
)
|
||||||
return order
|
if order:
|
||||||
|
bill = Bill.create_next_bill_for_order(order, ending_date=order.next_cancel_or_downgrade_date(order.starting_date))
|
||||||
|
payment= Payment.withdraw(owner=request.user, amount=one_time_price, notes=f"BILL #{bill.id}")
|
||||||
|
if payment:
|
||||||
|
#Close the bill as the payment has been added
|
||||||
|
VMInstance.create_instance(order)
|
||||||
|
bill.close()
|
||||||
|
|
||||||
|
return order, bill
|
|
@ -68,6 +68,7 @@ class OrderPaymentView(FormView):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(OrderPaymentView, self).get_context_data(**kwargs)
|
context = super(OrderPaymentView, self).get_context_data(**kwargs)
|
||||||
|
default_pricing = PricingPlan.get_default_pricing()
|
||||||
if 'billing_address_data' in self.request.session:
|
if 'billing_address_data' in self.request.session:
|
||||||
billing_address_form = BillingAddressForm(
|
billing_address_form = BillingAddressForm(
|
||||||
initial=self.request.session['billing_address_data']
|
initial=self.request.session['billing_address_data']
|
||||||
|
@ -80,21 +81,22 @@ class OrderPaymentView(FormView):
|
||||||
initial={'active': True, 'owner': self.request.user.id}
|
initial={'active': True, 'owner': self.request.user.id}
|
||||||
)
|
)
|
||||||
details_form = InitialRequestForm(
|
details_form = InitialRequestForm(
|
||||||
initial=self.request.session.get('order', {})
|
initial=self.request.session.get('order', {'pricing_name': default_pricing.name})
|
||||||
)
|
)
|
||||||
balance = get_balance_for_user(self.request.user)
|
balance = get_balance_for_user(self.request.user)
|
||||||
customer_id = uncloud_stripe.get_customer_id_for(self.request.user)
|
customer_id = uncloud_stripe.get_customer_id_for(self.request.user)
|
||||||
#TODO optimize this part for better performance
|
#TODO optimize this part for better performance
|
||||||
uncloud_stripe.sync_cards_for_user(self.request.user)
|
uncloud_stripe.sync_cards_for_user(self.request.user)
|
||||||
cards = uncloud_stripe.get_customer_cards(customer_id)
|
cards = uncloud_stripe.get_customer_cards(customer_id)
|
||||||
|
pricing = self.request.session.get('pricing', {'name': default_pricing.name, 'total': 0})
|
||||||
context.update({
|
context.update({
|
||||||
'matrix_vm_pricing': PricingPlan.get_by_name(self.request.session.get('pricing', {'name': 'unknown'})['name']),
|
'matrix_vm_pricing': PricingPlan.get_by_name(pricing['name']),
|
||||||
'billing_address_form': billing_address_form,
|
'billing_address_form': billing_address_form,
|
||||||
'details_form': details_form,
|
'details_form': details_form,
|
||||||
'balance': balance,
|
'balance': balance,
|
||||||
'cards': cards,
|
'cards': cards,
|
||||||
'stripe_key': settings.STRIPE_PUBLIC_KEY,
|
'stripe_key': settings.STRIPE_PUBLIC_KEY,
|
||||||
'show_cards': True if balance < self.request.session.get('pricing')['total'] else False,
|
'show_cards': True if balance < pricing['total'] else False,
|
||||||
})
|
})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@ -103,8 +105,6 @@ class OrderPaymentView(FormView):
|
||||||
for k in ['vat_validation_status', 'token', 'id_payment_method', 'total']:
|
for k in ['vat_validation_status', 'token', 'id_payment_method', 'total']:
|
||||||
if request.session.get(k):
|
if request.session.get(k):
|
||||||
request.session.pop(k)
|
request.session.pop(k)
|
||||||
if 'order' not in request.session:
|
|
||||||
return HttpResponseRedirect(reverse('matrix:index'))
|
|
||||||
return self.render_to_response(self.get_context_data())
|
return self.render_to_response(self.get_context_data())
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
|
@ -213,19 +213,23 @@ class OrderConfirmationView(DetailView):
|
||||||
try:
|
try:
|
||||||
amount = get_balance_for_user(self.request.user) - decimal.Decimal(total)
|
amount = get_balance_for_user(self.request.user) - decimal.Decimal(total)
|
||||||
if (amount < 0):
|
if (amount < 0):
|
||||||
Payment.deposit(request.user, abs(max(amount, settings.MIN_PER_TRANSACTION)), source='stripe')
|
Payment.deposit(request.user, max(abs(amount), settings.MIN_PER_TRANSACTION), source='stripe')
|
||||||
order = finalize_order(request, customer,
|
amount = get_balance_for_user(self.request.user) - decimal.Decimal(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('matrix:order_confirmation')
|
||||||
|
)
|
||||||
|
order, bill = finalize_order(request, customer,
|
||||||
billing_address,
|
billing_address,
|
||||||
total,
|
total,
|
||||||
PricingPlan.get_by_name(self.request.session['pricing']['name']),
|
PricingPlan.get_by_name(self.request.session['pricing']['name']),
|
||||||
request.session.get('order'))
|
request.session.get('order'))
|
||||||
if order:
|
if order and bill:
|
||||||
bill = Bill.create_next_bill_for_order(order)
|
|
||||||
self.request.session['bill_id'] = bill.id
|
self.request.session['bill_id'] = bill.id
|
||||||
payment= Payment.withdraw(owner=request.user, amount=total, notes=f"BILL #{bill.id}")
|
|
||||||
if payment:
|
|
||||||
#Close the bill as the payment has been added
|
|
||||||
bill.close()
|
|
||||||
return HttpResponseRedirect(reverse('matrix:order_success'))
|
return HttpResponseRedirect(reverse('matrix:order_success'))
|
||||||
except CardError as e:
|
except CardError as e:
|
||||||
messages.add_message(
|
messages.add_message(
|
||||||
|
@ -252,6 +256,7 @@ class OrderSuccessView(DetailView):
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'order': self.request.session.get('order'),
|
'order': self.request.session.get('order'),
|
||||||
|
'bill_id': self.request.session['bill_id'],
|
||||||
'balance': get_balance_for_user(self.request.user)
|
'balance': get_balance_for_user(self.request.user)
|
||||||
}
|
}
|
||||||
if ('order' not in request.session):
|
if ('order' not in request.session):
|
||||||
|
@ -294,7 +299,7 @@ class OrdersView(ListView):
|
||||||
return super().dispatch(*args, **kwargs)
|
return super().dispatch(*args, **kwargs)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return Order.objects.filter(owner=self.request.user)
|
return Order.objects.filter(owner=self.request.user).order_by('-creation_date')
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
order = Order.objects.get(id=request.POST.get('order_id', 0))
|
order = Order.objects.get(id=request.POST.get('order_id', 0))
|
||||||
|
@ -310,7 +315,7 @@ class InstancesView(ListView):
|
||||||
return super().dispatch(*args, **kwargs)
|
return super().dispatch(*args, **kwargs)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return VMInstance.objects.filter(owner=self.request.user)
|
return VMInstance.objects.filter(owner=self.request.user).order_by('-creation_date')
|
||||||
|
|
||||||
class PaymentsView(ListView):
|
class PaymentsView(ListView):
|
||||||
template_name = "matrixhosting/payments.html"
|
template_name = "matrixhosting/payments.html"
|
||||||
|
|
|
@ -16,4 +16,4 @@ GITLAB_PROJECT_ID=
|
||||||
GITLAB_OAUTH_TOKEN=
|
GITLAB_OAUTH_TOKEN=
|
||||||
GITLAB_AUTHOR_EMAIL=
|
GITLAB_AUTHOR_EMAIL=
|
||||||
GITLAB_AUTHOR_NAME=
|
GITLAB_AUTHOR_NAME=
|
||||||
WKHTMLTOPDF_CMD=/usr/local/bin/wkhtmltopdf
|
WKHTMLTOPDF_CMD=
|
|
@ -856,7 +856,6 @@ class Order(models.Model):
|
||||||
|
|
||||||
def create_bill_record(self, bill):
|
def create_bill_record(self, bill):
|
||||||
br = None
|
br = None
|
||||||
|
|
||||||
if self.recurring_price != 0:
|
if self.recurring_price != 0:
|
||||||
records = BillRecord.objects.filter(order=self).all()
|
records = BillRecord.objects.filter(order=self).all()
|
||||||
if not records:
|
if not records:
|
||||||
|
|
|
@ -38,9 +38,11 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class PricingView(View):
|
class PricingView(View):
|
||||||
def get(self, request, **args):
|
def get(self, request, **args):
|
||||||
address = get_billing_address_for_user(self.request.user)
|
|
||||||
vat_rate = False
|
vat_rate = False
|
||||||
vat_validation_status = False
|
vat_validation_status = False
|
||||||
|
address = False
|
||||||
|
if self.request.user and self.request.user.is_authenticated:
|
||||||
|
address = get_billing_address_for_user(self.request.user)
|
||||||
if address:
|
if address:
|
||||||
vat_rate = VATRate.get_vat_rate(address)
|
vat_rate = VATRate.get_vat_rate(address)
|
||||||
vat_validation_status = "verified" if address.vat_number_validated_on and address.vat_number_verified else False
|
vat_validation_status = "verified" if address.vat_number_validated_on and address.vat_number_verified else False
|
||||||
|
|
Loading…
Reference in a new issue