transaction history
This commit is contained in:
parent
4f19af4b52
commit
b118f07df5
15 changed files with 6718 additions and 161 deletions
|
@ -7,7 +7,7 @@ from .forms import ChargeForm
|
||||||
|
|
||||||
from .. import db
|
from .. import db
|
||||||
from ..email import send_email
|
from ..email import send_email
|
||||||
from ..models import User, Deployment, Service, Region, Address, Domain, contact_proxmaster
|
from ..models import User, Transaction, Deployment, Service, Region, Address, Domain, contact_proxmaster
|
||||||
from ..decorators import admin_required, permission_required
|
from ..decorators import admin_required, permission_required
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
@ -31,19 +31,19 @@ def after_request(response):
|
||||||
@admin.route("/", methods=['GET'])
|
@admin.route("/", methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@admin_required
|
@admin_required
|
||||||
def index():
|
def list_items():
|
||||||
alldeployments = Deployment.query.order_by(Deployment.user_id.desc()).all()
|
alldeployments = Deployment.query.order_by(Deployment.user_id.desc()).all()
|
||||||
alldomains = Domain.query.order_by(Domain.user_id.desc()).all()
|
alldomains = Domain.query.order_by(Domain.user_id.desc()).all()
|
||||||
allservices = Service.query.order_by(Service.user_id.desc()).all()
|
allservices = Service.query.order_by(Service.date_last_charge.asc()).all()
|
||||||
alladdresses = Address.query.order_by(Address.user_id.asc()).all()
|
alladdresses = Address.query.order_by(Address.user_id.asc()).all()
|
||||||
return render_template('admin/index.html', deployments=alldeployments, domains=alldomains, services=allservices, addresses=alladdresses)
|
return render_template('admin/list_items.html', deployments=alldeployments, domains=alldomains, services=allservices, addresses=alladdresses)
|
||||||
|
|
||||||
@admin.route("/users", methods=['GET'])
|
@admin.route("/listusers", methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@admin_required
|
@admin_required
|
||||||
def users():
|
def list_users():
|
||||||
allusers = User.query.order_by(User.pid.asc()).all()
|
allusers = User.query.order_by(User.pid.asc()).all()
|
||||||
return render_template('admin/users.html', users=allusers)
|
return render_template('admin/list_users.html', users=allusers)
|
||||||
|
|
||||||
@admin.route("/charge/<int:user_pid>", methods=['GET', 'POST'])
|
@admin.route("/charge/<int:user_pid>", methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -52,13 +52,19 @@ def charge(user_pid=0):
|
||||||
cuser = User.query.filter_by(pid=user_pid).first()
|
cuser = User.query.filter_by(pid=user_pid).first()
|
||||||
form = ChargeForm()
|
form = ChargeForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
|
transaction = Transaction(user_id=int(cuser.pid), description='Account charged by staff', value=float(form.amount.data))
|
||||||
|
db.session.add(transaction)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
cuser.wallet += float(form.amount.data)
|
cuser.wallet += float(form.amount.data)
|
||||||
db.session.add(cuser)
|
db.session.add(cuser)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return redirect(url_for('admin.users'))
|
return redirect(url_for('admin.list_users'))
|
||||||
return render_template('admin/charge.html', form=form, usr=cuser)
|
return render_template('admin/charge.html', form=form, usr=cuser)
|
||||||
|
|
||||||
@admin.route("/dashboard/<int:user_pid>", methods=['GET', 'POST'])
|
|
||||||
|
|
||||||
|
@admin.route("/dashboard/<int:user_pid>", methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@admin_required
|
@admin_required
|
||||||
def dashboard(user_pid=0):
|
def dashboard(user_pid=0):
|
||||||
|
@ -113,7 +119,26 @@ def dashboard(user_pid=0):
|
||||||
send_email(current_app.config['MAIL_USERNAME'], 'Cube {} is unreachable'.format(cubeid),
|
send_email(current_app.config['MAIL_USERNAME'], 'Cube {} is unreachable'.format(cubeid),
|
||||||
'vmanager/email/adm_unreachable', user=cuser, cubeid=cubeid )
|
'vmanager/email/adm_unreachable', user=cuser, cubeid=cubeid )
|
||||||
|
|
||||||
current_app.logger.info('[{}] deployments: {}, domains: {}, services: {}'.format(cuser.email, inv_deploynames, inv_services, inv_domains, inv_addresses ))
|
current_app.logger.info('[{}] deployments: {}, services: {}, domains: {}, services: {}'.format(cuser.email, inv_deploynames, inv_services, inv_domains, inv_addresses ))
|
||||||
return render_template('vmanager/dashboard.html', rrd=rrd, status=statuses, inv_deployments=deployments, inv_services=services, inv_domains=domains, inv_addresses=addresses)
|
return render_template('vmanager/dashboard.html', rrd=rrd, status=statuses, inv_deployments=deployments, inv_services=services, inv_domains=domains, inv_addresses=addresses)
|
||||||
|
|
||||||
|
@admin.route("/listtransactions", methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def list_transactions():
|
||||||
|
alltransactions = Transaction.query.order_by(Transaction.date_created.desc()).all()
|
||||||
|
return render_template('admin/list_transactions.html', transactions=alltransactions)
|
||||||
|
|
||||||
|
@admin.route("/transaction/<int:user_pid>", methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def transaction(user_pid=0):
|
||||||
|
cuser = User.query.filter_by(pid=user_pid).first()
|
||||||
|
transactions = cuser.inv_transactions.order_by(Transaction.date_created.desc()).all()
|
||||||
|
translist = []
|
||||||
|
for tr in transactions:
|
||||||
|
translist.append(tr.value)
|
||||||
|
|
||||||
|
current_app.logger.info('[{}] transactions: {}'.format(cuser.email, translist))
|
||||||
|
return render_template('uinvoice/transactions.html', transactions=transactions, translist=translist)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ from flask_login import login_required, login_user, logout_user, current_user
|
||||||
|
|
||||||
from . import auth
|
from . import auth
|
||||||
from .. import db
|
from .. import db
|
||||||
from ..models import User
|
from ..models import User, Transaction
|
||||||
from ..email import send_email
|
from ..email import send_email
|
||||||
from .forms import LoginForm, TwoFAForm, RegistrationForm, ChangePasswordForm,PasswordResetRequestForm, PasswordResetForm
|
from .forms import LoginForm, TwoFAForm, RegistrationForm, ChangePasswordForm,PasswordResetRequestForm, PasswordResetForm
|
||||||
|
|
||||||
|
@ -136,9 +136,14 @@ def register():
|
||||||
page = { 'title': 'Register' }
|
page = { 'title': 'Register' }
|
||||||
form = RegistrationForm()
|
form = RegistrationForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
user = User(email=form.email.data, password=form.password.data)
|
user = User(email=form.email.data, password=form.password.data, wallet=current_app.config['REGISTER_BONUS'])
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
transaction = Transaction(user_id=int(user.pid), description='Registered account bonus', value=current_app.config['REGISTER_BONUS'])
|
||||||
|
db.session.add(transaction)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
token = user.generate_confirmation_token()
|
token = user.generate_confirmation_token()
|
||||||
send_email(user.email, 'Потвърдете_вашият_акаунт', 'auth/email/confirm', user=user, token=token)
|
send_email(user.email, 'Потвърдете_вашият_акаунт', 'auth/email/confirm', user=user, token=token)
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ class User(db.Model, UserMixin):
|
||||||
|
|
||||||
group = db.Column(db.String(24), default='User')
|
group = db.Column(db.String(24), default='User')
|
||||||
language = db.Column(db.String(2), default='BG')
|
language = db.Column(db.String(2), default='BG')
|
||||||
wallet = db.Column(db.Float, default=0.0)
|
wallet = db.Column(db.Float)
|
||||||
currency = db.Column(db.String(3), default='BGN')
|
currency = db.Column(db.String(3), default='BGN')
|
||||||
|
|
||||||
inv_deployments = db.relationship('Deployment', backref='owner', lazy='dynamic')
|
inv_deployments = db.relationship('Deployment', backref='owner', lazy='dynamic')
|
||||||
|
@ -89,6 +89,8 @@ class User(db.Model, UserMixin):
|
||||||
inv_domains = db.relationship('Domain', backref='owner', lazy='dynamic')
|
inv_domains = db.relationship('Domain', backref='owner', lazy='dynamic')
|
||||||
inv_addresses = db.relationship('Address', backref='owner', lazy='dynamic')
|
inv_addresses = db.relationship('Address', backref='owner', lazy='dynamic')
|
||||||
|
|
||||||
|
inv_transactions = db.relationship('Transaction', backref='owner', lazy='dynamic')
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(User, self).__init__(**kwargs)
|
super(User, self).__init__(**kwargs)
|
||||||
if self.role is None:
|
if self.role is None:
|
||||||
|
@ -333,6 +335,7 @@ class Transaction(db.Model):
|
||||||
user_id = db.Column(db.Integer, db.ForeignKey('users.pid')) #FK
|
user_id = db.Column(db.Integer, db.ForeignKey('users.pid')) #FK
|
||||||
date_created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
|
date_created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
|
||||||
currency = db.Column(db.String, default='BGN')
|
currency = db.Column(db.String, default='BGN')
|
||||||
|
description = db.Column(db.String)
|
||||||
value = db.Column(db.Float)
|
value = db.Column(db.Float)
|
||||||
|
|
||||||
class Invoice(db.Model):
|
class Invoice(db.Model):
|
||||||
|
|
6434
app/static/css/theme_geo.css
Normal file
6434
app/static/css/theme_geo.css
Normal file
File diff suppressed because it is too large
Load diff
|
@ -2,8 +2,9 @@
|
||||||
<div class="panel panel-warning" id="prxadmin">
|
<div class="panel panel-warning" id="prxadmin">
|
||||||
<div class="panel-heading">Admin Pages</div>
|
<div class="panel-heading">Admin Pages</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<button class="btn btn-default" onclick="window.open('{{ url_for('admin.index') }}','_self')"><span class="glyphicon glyphicon-list" aria-hidden="true"></span> Item Index</button>
|
<button class="btn btn-default" onclick="window.open('{{ url_for('admin.list_items') }}','_self')"><span class="glyphicon glyphicon-list" aria-hidden="true"></span> Items List</button>
|
||||||
<button class="btn btn-default" onclick="window.open('{{ url_for('admin.users') }}','_self')"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> List All Users</button>
|
<button class="btn btn-default" onclick="window.open('{{ url_for('admin.list_users') }}','_self')"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Users List</button>
|
||||||
|
<button class="btn btn-default" onclick="window.open('{{ url_for('admin.list_transactions') }}','_self')"><span class="glyphicon glyphicon-usd" aria-hidden="true"></span> Transaction List</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page_content %}
|
{% block page_content %}
|
||||||
<div class="container-fluid">
|
|
||||||
<br />
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% include "admin/admin_tasks.html" %}
|
{% include "admin/admin_tasks.html" %}
|
||||||
|
|
||||||
|
@ -25,6 +23,7 @@
|
||||||
<th>HDD</th>
|
<th>HDD</th>
|
||||||
<th>Owner</th>
|
<th>Owner</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for deploy in deployments %}
|
{% for deploy in deployments %}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -41,6 +40,39 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="panel panel-danger" id="services">
|
||||||
|
<div class="panel-heading">Services</div>
|
||||||
|
<div class="panel-body"><p>
|
||||||
|
<table class="table table-hover table-striped table-condensed cf">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Category</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Price</th>
|
||||||
|
<th>Period (Months)</th>
|
||||||
|
<th>Last Charged</th>
|
||||||
|
<th>Owner</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for service in services %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ service.category }}</td>
|
||||||
|
<td>{{ service.description }}</td>
|
||||||
|
<td>{{ service.price }}</td>
|
||||||
|
<td>{{ service.period }}</td>
|
||||||
|
<td>{{ moment(service.date_last_charge).fromNow() }}</td>
|
||||||
|
<td><a href="{{ url_for('admin.dashboard', user_pid=service.user_id) }}">{{ service.owner.email }}</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="panel panel-danger" id="domains">
|
<div class="panel panel-danger" id="domains">
|
||||||
<div class="panel-heading">Domains</div>
|
<div class="panel-heading">Domains</div>
|
||||||
|
@ -52,6 +84,7 @@
|
||||||
<th>Expiry Date</th>
|
<th>Expiry Date</th>
|
||||||
<th>Owner</th>
|
<th>Owner</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for domain in domains %}
|
{% for domain in domains %}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -74,16 +107,17 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>IP</th>
|
<th>IP</th>
|
||||||
<th>Reverse DNS</th>
|
|
||||||
<th>MAC Addr.</th>
|
<th>MAC Addr.</th>
|
||||||
|
<th>Reverse DNS</th>
|
||||||
<th>Owner</th>
|
<th>Owner</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for address in addresses %}
|
{% for address in addresses %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ address.ip }}</td>
|
<td>{{ address.ip }}</td>
|
||||||
<td>{{ address.rdns }}</td>
|
|
||||||
<td>{{ address.mac }}</td>
|
<td>{{ address.mac }}</td>
|
||||||
|
<td>{{ address.rdns }}</td>
|
||||||
<td><a href="{{ url_for('admin.dashboard', user_pid=address.user_id) }}">{{ address.owner.email }}</a></td>
|
<td><a href="{{ url_for('admin.dashboard', user_pid=address.user_id) }}">{{ address.owner.email }}</a></td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -93,33 +127,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-12">
|
|
||||||
<div class="panel panel-danger" id="services">
|
|
||||||
<div class="panel-heading">Services</div>
|
|
||||||
<div class="panel-body"><p>
|
|
||||||
<table class="table table-hover table-striped table-condensed cf">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Description</th>
|
|
||||||
<th>Unit</th>
|
|
||||||
<th>Price</th>
|
|
||||||
</tr>
|
|
||||||
<tbody>
|
|
||||||
{% for service in services %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ service.name }}</td>
|
|
||||||
<td>{{ service.description }}</td>
|
|
||||||
<td>{{ service.unit }}</td>
|
|
||||||
<td>{{ service.unitprice }}</td>
|
|
||||||
<td><a href="{{ url_for('admin.dashboard', user_pid=service.user_id) }}">{{ service.owner.email }}</a></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
55
app/templates/admin/list_transactions.html
Normal file
55
app/templates/admin/list_transactions.html
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block page_content %}
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
{% include "admin/admin_tasks.html" %}
|
||||||
|
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="panel panel-danger">
|
||||||
|
<div class="panel-heading">Transactions</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover table-striped table-condensed cf">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{% for transaction in transactions %}
|
||||||
|
{% if transaction.value > 0 %}
|
||||||
|
<tr class="default">
|
||||||
|
<td><span class="glyphicon glyphicon-asterisk"></span></td>
|
||||||
|
<td>{{ transaction.description }}</td>
|
||||||
|
<td>{{ transaction.value }} {{ transaction.currency }}</td>
|
||||||
|
<td>{{ transaction.date_created.strftime('%d %b %Y - %H:%m') }}</td>
|
||||||
|
<td><a href="{{ url_for('admin.transaction', user_pid=transaction.owner.pid) }}">{{ transaction.owner.email }}</a></td>
|
||||||
|
{% else %}
|
||||||
|
<tr class="success">
|
||||||
|
<td><span class="glyphicon glyphicon-plus"></span></td>
|
||||||
|
<td>{{ transaction.description }}</td>
|
||||||
|
<td>{{ transaction.value }} {{ transaction.currency }}</td>
|
||||||
|
<td>{{ transaction.date_created.strftime('%d %b %Y - %H:%m') }}</td>
|
||||||
|
<td><a href="{{ url_for('admin.transaction', user_pid=transaction.owner.pid) }}">{{ transaction.owner.email }}</a></td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<td>last seen</td>
|
<td>last seen</td>
|
||||||
<td>last ip</td>
|
<td>last ip</td>
|
||||||
<td>wallet</td>
|
<td>wallet</td>
|
||||||
<td>cntrl</td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
<td>{{ moment(usr.last_seen).fromNow()}}</td>
|
<td>{{ moment(usr.last_seen).fromNow()}}</td>
|
||||||
<td>{{ usr.last_ip }}</td>
|
<td>{{ usr.last_ip }}</td>
|
||||||
<td><a href="{{ url_for('admin.charge', user_pid=usr.pid) }}">{{ usr.wallet }}</a></td>
|
<td><a href="{{ url_for('admin.charge', user_pid=usr.pid) }}">{{ usr.wallet }}</a></td>
|
||||||
<td><a href="{{ url_for('admin.dashboard', user_pid=usr.pid) }}">Inventory</a></td>
|
<td><a href="{{ url_for('admin.dashboard', user_pid=usr.pid) }}">Dashboard</a></td>
|
||||||
</td>
|
</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
|
@ -38,8 +38,10 @@
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
{% block page_content %}{% endblock %}
|
{% block page_content %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% block footer %}
|
{% block footer %}
|
||||||
{% include "footer_simple.html" %}
|
{% include "footer_simple.html" %}
|
||||||
|
|
|
@ -44,13 +44,13 @@
|
||||||
<li><a href="{{ url_for('auth.login') }}">Login</a></li>
|
<li><a href="{{ url_for('auth.login') }}">Login</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if current_user.is_administrator() %}
|
{% if current_user.is_administrator() %}
|
||||||
<li><a href="{{ url_for('admin.index') }}"><span class="glyphicon glyphicon-wrench"></span> Admin Panel</a></li>
|
<li><a href="{{ url_for('admin.list_items') }}"><span class="glyphicon glyphicon-wrench"></span> Admin Panel</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><img class="avatar" src="{{ current_user.gravatar(20) }}"> {{ current_user.email }} <span class="caret"></span></a>
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><img class="avatar" src="{{ current_user.gravatar(20) }}"> {{ current_user.email }} <span class="caret"></span></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a href="{{ url_for('vmanager.dashboard') }}"><span class="glyphicon glyphicon-eye-open"></span> Dashboard</a></li>
|
<li><a href="{{ url_for('vmanager.dashboard') }}"><span class="glyphicon glyphicon-eye-open"></span> Dashboard</a></li>
|
||||||
<li><a href="{{ url_for('uinvoice.documents') }}"><span class="glyphicon glyphicon-list-alt"></span> Orders</a></li>
|
<li><a href="{{ url_for('uinvoice.transactions') }}"><span class="glyphicon glyphicon-list-alt"></span> Transactions</a></li>
|
||||||
<li role="separator" class="divider"></li>
|
<li role="separator" class="divider"></li>
|
||||||
<li><a href="{{ url_for('settings.profile') }}"><span class="glyphicon glyphicon-user"></span> Profile</a></li>
|
<li><a href="{{ url_for('settings.profile') }}"><span class="glyphicon glyphicon-user"></span> Profile</a></li>
|
||||||
<li><a href="{{ url_for('auth.logout') }}"><span class="glyphicon glyphicon-off"></span> Logout</a></li>
|
<li><a href="{{ url_for('auth.logout') }}"><span class="glyphicon glyphicon-off"></span> Logout</a></li>
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block title %}Фактури{% endblock %}
|
|
||||||
|
|
||||||
{% block page_content %}
|
|
||||||
<div class="page-header">
|
|
||||||
<h1>Фактури</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
<br />
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-12">
|
|
||||||
<div class="panel panel-info">
|
|
||||||
<div class="panel-heading">Издадени Фактури</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Document ID</th>
|
|
||||||
<th>Date</th>
|
|
||||||
<th>Amount</th>
|
|
||||||
<th> </th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
{% for invoice in documents %}
|
|
||||||
{% if invoice.paid %}
|
|
||||||
<tr class="success">
|
|
||||||
<td>{{ invoice.pid }}</td>
|
|
||||||
<td>{{ invoice.date_created.strftime('%d %b %Y - %H:%m') }}</td>
|
|
||||||
<td>{{ invoice.amount }}</td>
|
|
||||||
<td><a href='invoice/{{ invoice.pid }}'>Preview</a></td>
|
|
||||||
<td> </td>
|
|
||||||
{% else %}
|
|
||||||
<tr class="danger">
|
|
||||||
<td>{{ invoice.pid }}</td>
|
|
||||||
<td>{{ invoice.date_created.strftime('%d %b %Y - %H:%m') }}</td>
|
|
||||||
<td>{{ invoice.amount }}</td>
|
|
||||||
<td><a href='invoice/{{ invoice.pid }}'>Pay</a></td>
|
|
||||||
{% endif %}
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
90
app/templates/uinvoice/transactions.html
Normal file
90
app/templates/uinvoice/transactions.html
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{{ super() }}
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js" integrity="sha256-SiHXR50l06UwJvHhFY4e5vzwq75vEHH+8fFNpkXePr0=" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
Chart.defaults.global.hover.mode = 'nearest';
|
||||||
|
var ctx = document.getElementById("transchart").getContext('2d');
|
||||||
|
var myChart = new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
|
||||||
|
datasets: [{
|
||||||
|
label: "History",
|
||||||
|
data: {{ translist }},
|
||||||
|
fill: false,
|
||||||
|
borderColor: "rgb(75, 192, 192)",
|
||||||
|
lineTension:0.1 }]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
hover: {
|
||||||
|
// Overrides the global setting
|
||||||
|
mode: 'index'
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
yAxes: [{
|
||||||
|
ticks: {
|
||||||
|
beginAtZero:true
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block page_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="panel panel-info">
|
||||||
|
<div class="panel-heading">Transactions</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
|
||||||
|
<canvas id="transchart" height="80"></canvas>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover table-striped table-condensed cf">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th>Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{% for transaction in transactions %}
|
||||||
|
{% if transaction.value > 0 %}
|
||||||
|
<tr class="success">
|
||||||
|
<td><span class="glyphicon glyphicon-plus"></span></td>
|
||||||
|
<td>{{ transaction.description }}</td>
|
||||||
|
<td>{{ transaction.value }} {{ transaction.currency }}</td>
|
||||||
|
<td>{{ transaction.date_created.strftime('%d %b %Y - %H:%m') }}</td>
|
||||||
|
{% else %}
|
||||||
|
<tr class="danger">
|
||||||
|
<td><span class="glyphicon glyphicon-minus"></span></td>
|
||||||
|
<td>{{ transaction.description }}</td>
|
||||||
|
<td>{{ transaction.value }} {{ transaction.currency }}</td>
|
||||||
|
<td>{{ transaction.date_created.strftime('%d %b %Y - %H:%m') }}</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -113,8 +113,6 @@ addEventListener("DOMContentLoaded", function() {
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page_content %}
|
{% block page_content %}
|
||||||
<div class="container-fluid">
|
|
||||||
<br />
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
|
@ -160,6 +158,38 @@ addEventListener("DOMContentLoaded", function() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="panel panel-info" id="services">
|
||||||
|
<div class="panel-heading">Services</div>
|
||||||
|
<div class="panel-body"><p>
|
||||||
|
<div id="no-more-tables">
|
||||||
|
<table class="table table-hover table-striped table-condensed cf">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Category</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Price</th>
|
||||||
|
<th>Period (In Months)</th>
|
||||||
|
<th>Last Charged</th>
|
||||||
|
</tr>
|
||||||
|
<tbody>
|
||||||
|
{% for service in inv_services %}
|
||||||
|
<tr>
|
||||||
|
<td data-title="Category">{{ service.category }}</td>
|
||||||
|
<td data-title="Description" >{{ service.description }}</td>
|
||||||
|
<td data-title="Price">{{ service.price }}</td>
|
||||||
|
<td data-title="Period (In Months)">{{ service.period }}</td>
|
||||||
|
<td data-title="Last Charged">{{ moment(service.date_last_charge).fromNow() }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-default" onclick="window.open('{{ url_for('main.index') }}')"><span class="glyphicon glyphicon-plus" aria-hiddent="true"></span> Order</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="panel panel-info" id="domains">
|
<div class="panel panel-info" id="domains">
|
||||||
<div class="panel-heading">Domains</div>
|
<div class="panel-heading">Domains</div>
|
||||||
|
@ -218,43 +248,11 @@ addEventListener("DOMContentLoaded", function() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-12">
|
|
||||||
<div class="panel panel-info" id="services">
|
|
||||||
<div class="panel-heading">Services</div>
|
|
||||||
<div class="panel-body"><p>
|
|
||||||
<div id="no-more-tables">
|
|
||||||
<table class="table table-hover table-striped table-condensed cf">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Description</th>
|
|
||||||
<th>Unit</th>
|
|
||||||
<th>Price</th>
|
|
||||||
</tr>
|
|
||||||
<tbody>
|
|
||||||
{% for service in inv_services %}
|
|
||||||
<tr>
|
|
||||||
<td data-title="Name">{{ service.name }}</td>
|
|
||||||
<td data-title="Description" >{{ service.description }}</td>
|
|
||||||
<td data-title="Unit">{{ service.unit }}</td>
|
|
||||||
<td data-title="Price">{{ service.unitprice }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-default" onclick="window.open('{{ url_for('main.index') }}')"><span class="glyphicon glyphicon-plus" aria-hiddent="true"></span> Order</button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ from .forms import PaymentForm
|
||||||
|
|
||||||
from ..email import send_email
|
from ..email import send_email
|
||||||
from .. import db
|
from .. import db
|
||||||
from ..models import User, Invoice
|
from ..models import User, Transaction
|
||||||
|
|
||||||
#INVOICES
|
#INVOICES
|
||||||
#@uinvoice.route('/charge', methods=['GET', 'POST'])
|
#@uinvoice.route('/charge', methods=['GET', 'POST'])
|
||||||
|
@ -27,20 +27,22 @@ from ..models import User, Invoice
|
||||||
# return redirect(url_for('uinvoice.documents'))
|
# return redirect(url_for('uinvoice.documents'))
|
||||||
# return render_template('uinvoice/charge.html', page=page, form=form)
|
# return render_template('uinvoice/charge.html', page=page, form=form)
|
||||||
|
|
||||||
@uinvoice.route('/documents', methods=['GET'])
|
@uinvoice.route('/transactions', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def documents():
|
def transactions():
|
||||||
page = { 'title': 'Invoice documents' }
|
page = { 'title': 'Payment Transaction' }
|
||||||
invoices = Invoice.query.filter_by(user_id=current_user.pid).order_by(desc(Invoice.date_created)).all()
|
transactions = Transaction.query.filter_by(user_id=current_user.pid).order_by(Transaction.date_created.asc()).all()
|
||||||
db.session.commit()
|
translist = []
|
||||||
return render_template('uinvoice/documents.html', page=page, documents=invoices)
|
for tr in transactions:
|
||||||
|
translist.append(tr.value)
|
||||||
|
return render_template('uinvoice/transactions.html', page=page, transactions=transactions, translist=translist)
|
||||||
|
|
||||||
|
|
||||||
@uinvoice.route('/order/<int:document_id>', methods=['GET', 'POST'])
|
@uinvoice.route('/order/<int:document_id>', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def order(document_id):
|
def order(document_id):
|
||||||
page = { 'title': 'Preview ' + str(document_id) }
|
page = { 'title': 'Preview ' + str(document_id) }
|
||||||
order = Invoice.query.filter_by(pid=document_id).first()
|
order = Transaction.query.filter_by(pid=document_id).first()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
#check if document_id is owned by you.
|
#check if document_id is owned by you.
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -131,7 +131,7 @@ def dashboard():
|
||||||
inv_deploycubeids.extend([invcls.machine_id])
|
inv_deploycubeids.extend([invcls.machine_id])
|
||||||
inv_deploynames.extend([invcls.machine_alias])
|
inv_deploynames.extend([invcls.machine_alias])
|
||||||
|
|
||||||
services = cuser.inv_services.order_by(Service.date_created.desc()).all()
|
services = cuser.inv_services.order_by(Service.date_last_charge.asc()).all()
|
||||||
inv_services = []
|
inv_services = []
|
||||||
for invcls in services:
|
for invcls in services:
|
||||||
if invcls.user_id == cuser.pid and invcls.enabled == True:
|
if invcls.user_id == cuser.pid and invcls.enabled == True:
|
||||||
|
@ -174,7 +174,7 @@ def dashboard():
|
||||||
send_email(current_app.config['MAIL_USERNAME'], 'Cube {} is unreachable'.format(cubeid),
|
send_email(current_app.config['MAIL_USERNAME'], 'Cube {} is unreachable'.format(cubeid),
|
||||||
'vmanager/email/adm_unreachable', user=current_user, cubeid=cubeid )
|
'vmanager/email/adm_unreachable', user=current_user, cubeid=cubeid )
|
||||||
|
|
||||||
current_app.logger.info('[{}] deployments: {}, domains: {}, services: {}'.format(current_user.email, inv_deploynames, inv_services, inv_domains, inv_addresses ))
|
current_app.logger.info('[{}] deployments: {}, services: {}, domains: {}, addresses: {}'.format(current_user.email, inv_deploynames, inv_services, inv_domains, inv_addresses ))
|
||||||
return render_template('vmanager/dashboard.html', rrd=rrd, status=statuses, inv_deployments=deployments, inv_services=services, inv_domains=domains, inv_addresses=addresses)
|
return render_template('vmanager/dashboard.html', rrd=rrd, status=statuses, inv_deployments=deployments, inv_services=services, inv_domains=domains, inv_addresses=addresses)
|
||||||
|
|
||||||
@vmanager.route('/vmvnc/<int:vmid>')
|
@vmanager.route('/vmvnc/<int:vmid>')
|
||||||
|
|
Loading…
Reference in a new issue