Compare commits
6 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8ab7beb0be | ||
![]() |
4448b6b28f | ||
![]() |
fabe9094a2 | ||
![]() |
3b50557a6a | ||
![]() |
8799790cfd | ||
![]() |
fb2455247a |
76 changed files with 2284 additions and 0 deletions
19
remove_yuyu_demo.sh
Executable file
19
remove_yuyu_demo.sh
Executable file
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Specify Horizon Location (ex: /etc/horizon): "
|
||||||
|
read horizon_path
|
||||||
|
root=`pwd -P`
|
||||||
|
|
||||||
|
echo "Removing yuyu demo Symlink"
|
||||||
|
rm $horizon_path/openstack_dashboard/dashboards/yuyu_demo
|
||||||
|
rm $horizon_path/openstack_dashboard/local/enabled/_6600_yuyu.py
|
||||||
|
rm $horizon_path/openstack_dashboard/local/enabled/_6601_admin_billing_panel_group.py
|
||||||
|
rm $horizon_path/openstack_dashboard/local/enabled/_6602_admin_billing_overview.py
|
||||||
|
rm $horizon_path/openstack_dashboard/local/enabled/_6603_admin_billing_price_configuration.py
|
||||||
|
rm $horizon_path/openstack_dashboard/local/enabled/_6604_admin_billing_setting.py
|
||||||
|
rm $horizon_path/openstack_dashboard/local/enabled/_6604_admin_billing_setting.py
|
||||||
|
rm $horizon_path/openstack_dashboard/local/enabled/_6605_admin_billing_projects_invoice.py
|
||||||
|
rm $horizon_path/openstack_dashboard/local/enabled/_6606_admin_notification_center.py
|
||||||
|
rm $horizon_path/openstack_dashboard/local/enabled/_6607_admin_billing_projects_balance.py
|
||||||
|
|
||||||
|
echo "Yuyu Demo Removal Done"
|
20
setup_yuyu_demo.sh
Executable file
20
setup_yuyu_demo.sh
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Specify Horizon Location (ex: /etc/horizon): "
|
||||||
|
read horizon_path
|
||||||
|
root=`pwd -P`
|
||||||
|
|
||||||
|
echo "Creating Symlink"
|
||||||
|
ln -sf $root/yuyu_demo $horizon_path/openstack_dashboard/dashboards
|
||||||
|
ln -sf $root/yuyu_demo/local/enabled/_6600_yuyu_demo.py $horizon_path/openstack_dashboard/local/enabled/_6600_yuyu_demo.py
|
||||||
|
ln -sf $root/yuyu_demo/local/enabled/_6601_admin_billing_panel_group.py $horizon_path/openstack_dashboard/local/enabled/_6601_admin_billing_panel_group.py
|
||||||
|
ln -sf $root/yuyu_demo/local/enabled/_6602_admin_billing_overview.py $horizon_path/openstack_dashboard/local/enabled/_6602_admin_billing_overview.py
|
||||||
|
ln -sf $root/yuyu_demo/local/enabled/_6603_admin_billing_price_configuration.py $horizon_path/openstack_dashboard/local/enabled/_6603_admin_billing_price_configuration.py
|
||||||
|
ln -sf $root/yuyu_demo/local/enabled/_6604_admin_billing_setting.py $horizon_path/openstack_dashboard/local/enabled/_6604_admin_billing_setting.py
|
||||||
|
ln -sf $root/yuyu_demo/local/enabled/_6604_admin_billing_setting.py $horizon_path/openstack_dashboard/local/enabled/_6604_admin_billing_setting.py
|
||||||
|
ln -sf $root/yuyu_demo/local/enabled/_6605_admin_billing_projects_invoice.py $horizon_path/openstack_dashboard/local/enabled/_6605_admin_billing_projects_invoice.py
|
||||||
|
ln -sf $root/yuyu_demo/local/enabled/_6606_admin_notification_center.py $horizon_path/openstack_dashboard/local/enabled/_6605_admin_notification_center.py
|
||||||
|
ln -sf $root/yuyu_demo/local/enabled/_6607_admin_billing_projects_balance.py $horizon_path/openstack_dashboard/local/enabled/_6607_admin_billing_projects_balance.py
|
||||||
|
|
||||||
|
echo "Symlink Creation Done"
|
||||||
|
echo "Now you can configure and use yuyu dashboard"
|
0
yuyu_demo/__init__.py
Normal file
0
yuyu_demo/__init__.py
Normal file
0
yuyu_demo/admin/billing_overview_demo/__init__.py
Normal file
0
yuyu_demo/admin/billing_overview_demo/__init__.py
Normal file
21
yuyu_demo/admin/billing_overview_demo/panel.py
Normal file
21
yuyu_demo/admin/billing_overview_demo/panel.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
|
||||||
|
class BillingOverviewDemo(horizon.Panel):
|
||||||
|
name = _("Billing Overview")
|
||||||
|
slug = "billing_overview_demo"
|
||||||
|
|
19
yuyu_demo/admin/billing_overview_demo/urls.py
Normal file
19
yuyu_demo/admin/billing_overview_demo/urls.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
]
|
17
yuyu_demo/admin/billing_overview_demo/views.py
Normal file
17
yuyu_demo/admin/billing_overview_demo/views.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
import json
|
||||||
|
|
||||||
|
from ....yuyu.admin.billing_overview import views
|
||||||
|
|
||||||
|
class IndexView(views.IndexView):
|
||||||
|
pass
|
0
yuyu_demo/admin/billing_setting_demo/__init__.py
Normal file
0
yuyu_demo/admin/billing_setting_demo/__init__.py
Normal file
6
yuyu_demo/admin/billing_setting_demo/forms.py
Normal file
6
yuyu_demo/admin/billing_setting_demo/forms.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from ....yuyu.admin.billing_setting import forms
|
||||||
|
|
||||||
|
|
||||||
|
class SettingForm(forms.SettingForm):
|
||||||
|
def handle(self, request, data):
|
||||||
|
return
|
21
yuyu_demo/admin/billing_setting_demo/panel.py
Normal file
21
yuyu_demo/admin/billing_setting_demo/panel.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
|
||||||
|
class BillingSettingDemo(horizon.Panel):
|
||||||
|
name = _("Billing Setting")
|
||||||
|
slug = "billing_setting_demo"
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
{% if cancel_url %}
|
||||||
|
<a href="{% block cancel_url %}{{ cancel_url }}{% endblock %}"
|
||||||
|
class="btn btn-default cancel">
|
||||||
|
{{ cancel_label }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<input class="btn btn-primary" type="submit" disabled value="{{ submit_label }}">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans '<b>Company Name</b> : Your Company Name that will be included in invoice' %}</p>
|
||||||
|
<p>{% trans '<b>Company Logo</b> : A logo that will be used in invoice' %}</p>
|
||||||
|
<p>{% trans '<b>Email Admin</b> : Used to send a notification related invoice and error. You can put multiple email here separated by `,` (comma). Example: admin1@company.com,admin2@company.com' %}</p>
|
||||||
|
<p>{% trans '<b>Invoice Tax</b> : Tax that will be calculated for each invoice' %}</p>
|
||||||
|
<p>{% trans '<b>Invoice Auto Deduct Balance</b> : Automatically deduct project balance and finish invoice every end of the month if project balance is sufficient.' %}</p>
|
||||||
|
<p>{% trans '<b>How To Top Up</b> : Instruction how to top up project balance that can be seen by project user' %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}{% trans "Update Billing Setting" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "yuyu_demo/billing_setting_demo/_form_setting.html" %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,39 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Billing Setting" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "admin/price_configuration/missing_prices.html" %}
|
||||||
|
{% include "admin/billing_setting/missing_billing_setting.html" %}
|
||||||
|
|
||||||
|
{# Form #}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ table.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{% if setting.billing_enabled %}
|
||||||
|
<div class="panel panel-success">
|
||||||
|
<div class="panel-heading">Status: Billing Enabled</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<button class="btn btn-danger" data-toggle="modal" data-target="#modal_disable_billing">Disable Billing</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="panel panel-danger">
|
||||||
|
<div class="panel-heading">Status: Billing Disabled</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>Please make sure all price is already configured before enable billing</p>
|
||||||
|
<a href="{% url 'horizon:yuyu_demo:billing_setting_demo:enable_billing' %}" class="btn btn-primary {% if missing_price.has_missing or missing_setting.has_missing %} disabled {% endif %}">Enable</a>
|
||||||
|
<a href="{% url 'horizon:yuyu_demo:billing_setting_demo:reset_billing' %}" class="btn btn-danger">Reset Billing Data</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% include "admin/billing_setting/modal_disable_billing.html" with modal_backdrop='static' hide=True %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
{% if missing_setting.company_name %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
Company Name not complete
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if missing_setting.company_address %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
Company Address not complete
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if missing_setting.company_logo %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
Company Logo not complete
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if missing_setting.invoice_tax %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
Tax not complete
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if missing_setting.email_admin %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
Email Admin not complete
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{% extends "horizon/common/_modal.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal_id %}modal_disable_billing{% endblock %}
|
||||||
|
{% block modal_backdrop %}static{% endblock %}
|
||||||
|
{% block modal-header %}{% trans "Confirmation" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body %}
|
||||||
|
<p>{% trans "Are you sure to disable billing?" %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
<a href='#' class='btn btn-danger cancel' data-dismiss='modal'>{% trans "No" %}</a>
|
||||||
|
<a href="{% url 'horizon:admin:billing_setting:disable_billing' %}" class="btn btn-primary">{% trans "Yes" %}</a>
|
||||||
|
{% endblock %}
|
25
yuyu_demo/admin/billing_setting_demo/urls.py
Normal file
25
yuyu_demo/admin/billing_setting_demo/urls.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
url(r'^enable_billing$', views.EnableBillingView.as_view(), name='enable_billing'),
|
||||||
|
url(r'^disable_billing$', views.DisableBillingView.as_view(), name='disable_billing'),
|
||||||
|
url(r'^reset_billing$', views.ResetBillingView.as_view(), name='reset_billing'),
|
||||||
|
url(r'^update_setting/$',
|
||||||
|
views.UpdateSettingView.as_view(), name='update_setting'),
|
||||||
|
]
|
||||||
|
|
41
yuyu_demo/admin/billing_setting_demo/views.py
Normal file
41
yuyu_demo/admin/billing_setting_demo/views.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
from django import shortcuts
|
||||||
|
|
||||||
|
from ....yuyu.admin.billing_setting import views
|
||||||
|
from . import forms
|
||||||
|
|
||||||
|
class IndexView(views.IndexView):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateSettingView(views.UpdateSettingView):
|
||||||
|
form_class = forms.SettingForm
|
||||||
|
submit_url = ''
|
||||||
|
success_url = ''
|
||||||
|
template_name = 'yuyu_demo/billing_setting_demo/form_setting.html'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class EnableBillingView(views.EnableBillingView):
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
return shortcuts.redirect("horizon:yuyu_demo:billing_setting_demo:index")
|
||||||
|
|
||||||
|
|
||||||
|
class DisableBillingView(views.DisableBillingView):
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
return shortcuts.redirect("horizon:yuyu_demo:billing_setting_demo:index")
|
||||||
|
|
||||||
|
|
||||||
|
class ResetBillingView(views.ResetBillingView):
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
return shortcuts.redirect("horizon:yuyu_demo:billing_setting_demo:index")
|
0
yuyu_demo/admin/notification_center_demo/__init__.py
Normal file
0
yuyu_demo/admin/notification_center_demo/__init__.py
Normal file
21
yuyu_demo/admin/notification_center_demo/panel.py
Normal file
21
yuyu_demo/admin/notification_center_demo/panel.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationCenterDemo(horizon.Panel):
|
||||||
|
name = _("Notification Center")
|
||||||
|
slug = "notification_center_demo"
|
||||||
|
|
27
yuyu_demo/admin/notification_center_demo/urls.py
Normal file
27
yuyu_demo/admin/notification_center_demo/urls.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
url(r'^(?P<notification_id>[^/]+)/$',
|
||||||
|
views.DetailView.as_view(),
|
||||||
|
name='detail'),
|
||||||
|
url(r'^resend/(?P<notification_id>[^/]+)/$',
|
||||||
|
views.ResendView.as_view(),
|
||||||
|
name='resend'),
|
||||||
|
url(r'^read_all/(?P<selection>[^/]+)$', views.ReadAllView.as_view(), name='read_all'),
|
||||||
|
]
|
||||||
|
|
31
yuyu_demo/admin/notification_center_demo/views.py
Normal file
31
yuyu_demo/admin/notification_center_demo/views.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
from django import shortcuts
|
||||||
|
from ....yuyu.admin.notification_center import views
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(views.IndexView):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DetailView(views.DetailView):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ReadAllView(views.ReadAllView):
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
return shortcuts.redirect("horizon:yuyu_demo:notification_center_demo:index")
|
||||||
|
|
||||||
|
|
||||||
|
class ResendView(views.ResendView):
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
return shortcuts.redirect("horizon:yuyu_demo:notification_center_demo:index")
|
0
yuyu_demo/admin/price_configuration_demo/__init__.py
Normal file
0
yuyu_demo/admin/price_configuration_demo/__init__.py
Normal file
34
yuyu_demo/admin/price_configuration_demo/forms.py
Normal file
34
yuyu_demo/admin/price_configuration_demo/forms.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import forms
|
||||||
|
|
||||||
|
from ....yuyu.admin.price_configuration import forms
|
||||||
|
|
||||||
|
class FlavorPriceForm(forms.FlavorPriceForm):
|
||||||
|
def handle(self, request, data):
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class VolumePriceForm(forms.VolumePriceForm):
|
||||||
|
def handle(self, request, data):
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class FloatingIpPriceForm(forms.FloatingIpPriceForm):
|
||||||
|
def handle(self, request, data):
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class RouterPriceForm(forms.RouterPriceForm):
|
||||||
|
def handle(self, request, data):
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotPriceForm(forms.SnapshotPriceForm):
|
||||||
|
def handle(self, request, data):
|
||||||
|
return
|
||||||
|
|
||||||
|
class ImagePriceForm(forms.SnapshotPriceForm):
|
||||||
|
def handle(self, request, data):
|
||||||
|
return
|
21
yuyu_demo/admin/price_configuration_demo/panel.py
Normal file
21
yuyu_demo/admin/price_configuration_demo/panel.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
|
||||||
|
class PriceConfigurationDemo(horizon.Panel):
|
||||||
|
name = _("Price Configuration")
|
||||||
|
slug = "price_configuration_demo"
|
||||||
|
|
267
yuyu_demo/admin/price_configuration_demo/tables.py
Normal file
267
yuyu_demo/admin/price_configuration_demo/tables.py
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
from django.utils.translation import ugettext_lazy as _, ungettext_lazy
|
||||||
|
|
||||||
|
from horizon import tables
|
||||||
|
from ....yuyu.cases.flavor_price_use_case import FlavorPriceUseCase
|
||||||
|
from ....yuyu.cases.floating_ip_price_use_case import FloatingIpPriceUseCase
|
||||||
|
from ....yuyu.cases.volume_price_use_case import VolumePriceUseCase
|
||||||
|
from ....yuyu.cases.router_price_use_case import RouterPriceUseCase
|
||||||
|
from ....yuyu.cases.snapshot_price_use_case import SnapshotPriceUseCase
|
||||||
|
from ....yuyu.cases.image_price_use_case import ImagePriceUseCase
|
||||||
|
from ....yuyu.core.pricing_admin.tables import BasePriceTable, BaseCreatePrice, \
|
||||||
|
BaseEditPrice
|
||||||
|
|
||||||
|
|
||||||
|
class BaseDeletePrice(tables.DeleteAction):
|
||||||
|
use_case = None
|
||||||
|
single_action_label = None
|
||||||
|
plural_action_label = None
|
||||||
|
|
||||||
|
def action_present(self, count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
"Delete " + self.single_action_label,
|
||||||
|
"Delete " + self.plural_action_label,
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def action_past(self, count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
"Deleted " + self.single_action_label,
|
||||||
|
"Deleted " + self.plural_action_label,
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def delete(self, request, obj_id):
|
||||||
|
return
|
||||||
|
|
||||||
|
def create_create_action(type_name, **kwargs):
|
||||||
|
return type(type_name, (BaseCreatePrice,), kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def create_filter_action(type_name, **kwargs):
|
||||||
|
return type(type_name, (tables.FilterAction,), kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def create_edit_action(type_name, **kwargs):
|
||||||
|
return type(type_name, (BaseEditPrice,), kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def create_delete_action(type_name, **kwargs):
|
||||||
|
return type(type_name, (BaseDeletePrice,), kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class FlavorPriceTable(BasePriceTable):
|
||||||
|
name = tables.WrappingColumn('name', verbose_name=_('Flavor Name'))
|
||||||
|
|
||||||
|
def get_object_display(self, datum):
|
||||||
|
return datum['name']
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "flavor_price"
|
||||||
|
verbose_name = _("Flavor Price")
|
||||||
|
table_actions = (
|
||||||
|
create_filter_action(
|
||||||
|
type_name="FlavorPriceFilter",
|
||||||
|
name="flavor_price_filter"
|
||||||
|
),
|
||||||
|
create_create_action(
|
||||||
|
type_name="FlavorPriceCreate",
|
||||||
|
name="flavor_price_create",
|
||||||
|
verbose_name=_("Create Flavor Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:flavor_price_create"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
row_actions = (
|
||||||
|
create_edit_action(
|
||||||
|
type_name="FlavorPriceUpdate",
|
||||||
|
name="flavor_price_edit",
|
||||||
|
verbose_name=_("Edit Flavor Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:flavor_price_update"
|
||||||
|
),
|
||||||
|
create_delete_action(
|
||||||
|
type_name="FlavorPriceDelete",
|
||||||
|
use_case=FlavorPriceUseCase(),
|
||||||
|
single_action_label="Flavor Price",
|
||||||
|
plural_action_label="Flavor Prices"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class VolumePriceTable(BasePriceTable):
|
||||||
|
name = tables.WrappingColumn('name', verbose_name=_('Volume Type Name'))
|
||||||
|
|
||||||
|
def get_object_display(self, datum):
|
||||||
|
return datum['name']
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "volume_price"
|
||||||
|
verbose_name = _("Volume Price")
|
||||||
|
table_actions = (
|
||||||
|
create_filter_action(
|
||||||
|
type_name="VolumePriceFilter",
|
||||||
|
name="volume_price_filter"
|
||||||
|
),
|
||||||
|
create_create_action(
|
||||||
|
type_name="VolumePriceCreate",
|
||||||
|
name="create_volume_price",
|
||||||
|
verbose_name=_("Create Volume Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:volume_price_create"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
row_actions = (
|
||||||
|
create_edit_action(
|
||||||
|
type_name="VolumePriceEdit",
|
||||||
|
name="update_volume_price",
|
||||||
|
verbose_name=_("Edit Volume Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:volume_price_update"
|
||||||
|
),
|
||||||
|
create_delete_action(
|
||||||
|
type_name="VolumePriceDelete",
|
||||||
|
use_case=VolumePriceUseCase(),
|
||||||
|
single_action_label="Volume Price",
|
||||||
|
plural_action_label="Volume Prices"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FloatingIpPriceTable(BasePriceTable):
|
||||||
|
def get_object_display(self, datum):
|
||||||
|
return datum['id']
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "floating_ip_price"
|
||||||
|
verbose_name = _("Floating IP Price")
|
||||||
|
table_actions = (
|
||||||
|
create_filter_action(
|
||||||
|
type_name="FloatingIpPriceFilter",
|
||||||
|
name="floating_ip_price_filter"
|
||||||
|
),
|
||||||
|
create_create_action(
|
||||||
|
type_name="FloatingIpPriceCreate",
|
||||||
|
name="create_floating_ip_price",
|
||||||
|
verbose_name=_("Create Floating IP Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:floating_ip_price_create",
|
||||||
|
single_data=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
row_actions = (
|
||||||
|
create_edit_action(
|
||||||
|
type_name="FloatingIpPriceEdit",
|
||||||
|
name="update_floating_ip_price",
|
||||||
|
verbose_name=_("Edit Floating IP Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:floating_ip_price_update"
|
||||||
|
),
|
||||||
|
create_delete_action(
|
||||||
|
type_name="FloatingIpPriceDelete",
|
||||||
|
use_case=FloatingIpPriceUseCase(),
|
||||||
|
single_action_label="Floating IP Price",
|
||||||
|
plural_action_label="Floating IP Prices"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RouterPriceTable(BasePriceTable):
|
||||||
|
def get_object_display(self, datum):
|
||||||
|
return datum['id']
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "router_price"
|
||||||
|
verbose_name = _("Router Price")
|
||||||
|
table_actions = (
|
||||||
|
create_filter_action(
|
||||||
|
type_name="RouterPriceFilter",
|
||||||
|
name="router_price_filter"
|
||||||
|
),
|
||||||
|
create_create_action(
|
||||||
|
type_name="RouterPriceCreate",
|
||||||
|
name="create_router_price",
|
||||||
|
verbose_name=_("Create Router Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:router_price_create",
|
||||||
|
single_data=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
row_actions = (
|
||||||
|
create_edit_action(
|
||||||
|
type_name="RouterPriceEdit",
|
||||||
|
name="update_router_price",
|
||||||
|
verbose_name=_("Edit Router Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:router_price_update"
|
||||||
|
),
|
||||||
|
create_delete_action(
|
||||||
|
type_name="RouterPriceDelete",
|
||||||
|
use_case=RouterPriceUseCase(),
|
||||||
|
single_action_label="Router Price",
|
||||||
|
plural_action_label="Router Prices"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotPriceTable(BasePriceTable):
|
||||||
|
def get_object_display(self, datum):
|
||||||
|
return datum['id']
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "snapshot_price"
|
||||||
|
verbose_name = _("Snapshot Price")
|
||||||
|
table_actions = (
|
||||||
|
create_filter_action(
|
||||||
|
type_name="SnapshotFilter",
|
||||||
|
name="snapshot_price_filter"
|
||||||
|
),
|
||||||
|
create_create_action(
|
||||||
|
type_name="SnapshotCreate",
|
||||||
|
name="create_snapshot_price",
|
||||||
|
verbose_name=_("Create Snapshot Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:snapshot_price_create",
|
||||||
|
single_data=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
row_actions = (
|
||||||
|
create_edit_action(
|
||||||
|
type_name="SnapshotEdit",
|
||||||
|
name="update_snapshot_price",
|
||||||
|
verbose_name=_("Edit Snapshot Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:snapshot_price_update"
|
||||||
|
),
|
||||||
|
create_delete_action(
|
||||||
|
type_name="SnapshotDelete",
|
||||||
|
use_case=SnapshotPriceUseCase(),
|
||||||
|
single_action_label="Snapshot Price",
|
||||||
|
plural_action_label="Snapshot Prices"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ImagePriceTable(BasePriceTable):
|
||||||
|
def get_object_display(self, datum):
|
||||||
|
return datum['id']
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "image_price"
|
||||||
|
verbose_name = _("Image Price")
|
||||||
|
table_actions = (
|
||||||
|
create_filter_action(
|
||||||
|
type_name="ImageFilter",
|
||||||
|
name="image_price_filter"
|
||||||
|
),
|
||||||
|
create_create_action(
|
||||||
|
type_name="ImageCreate",
|
||||||
|
name="create_image_price",
|
||||||
|
verbose_name=_("Create Image Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:image_price_create",
|
||||||
|
single_data=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
row_actions = (
|
||||||
|
create_edit_action(
|
||||||
|
type_name="ImageEdit",
|
||||||
|
name="update_image_price",
|
||||||
|
verbose_name=_("Edit Image Price"),
|
||||||
|
url="horizon:yuyu_demo:price_configuration_demo:image_price_update"
|
||||||
|
),
|
||||||
|
create_delete_action(
|
||||||
|
type_name="ImageDelete",
|
||||||
|
use_case=ImagePriceUseCase(),
|
||||||
|
single_action_label="Image Price",
|
||||||
|
plural_action_label="Image Prices"
|
||||||
|
)
|
||||||
|
)
|
130
yuyu_demo/admin/price_configuration_demo/tabs.py
Normal file
130
yuyu_demo/admin/price_configuration_demo/tabs.py
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
from horizon import exceptions, tables, tabs
|
||||||
|
from .tables import FlavorPriceTable, VolumePriceTable, \
|
||||||
|
FloatingIpPriceTable, RouterPriceTable, SnapshotPriceTable, ImagePriceTable
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.yuyu.cases.flavor_price_use_case import FlavorPriceUseCase
|
||||||
|
from openstack_dashboard.dashboards.yuyu.cases.floating_ip_price_use_case import FloatingIpPriceUseCase
|
||||||
|
from openstack_dashboard.dashboards.yuyu.cases.volume_price_use_case import VolumePriceUseCase
|
||||||
|
from openstack_dashboard.dashboards.yuyu.cases.router_price_use_case import RouterPriceUseCase
|
||||||
|
from openstack_dashboard.dashboards.yuyu.cases.snapshot_price_use_case import SnapshotPriceUseCase
|
||||||
|
from openstack_dashboard.dashboards.yuyu.cases.image_price_use_case import ImagePriceUseCase
|
||||||
|
|
||||||
|
|
||||||
|
class FlavorTab(tabs.TableTab):
|
||||||
|
table_classes = (FlavorPriceTable,)
|
||||||
|
name = _("Flavor")
|
||||||
|
slug = "flavor"
|
||||||
|
template_name = 'horizon/common/_detail_table.html'
|
||||||
|
|
||||||
|
flavor_price_uc = FlavorPriceUseCase()
|
||||||
|
|
||||||
|
def get_flavor_price_data(self):
|
||||||
|
try:
|
||||||
|
data = self.flavor_price_uc.list(self.request)
|
||||||
|
return data
|
||||||
|
except Exception:
|
||||||
|
error_message = _('Unable to get flavor prices')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeTab(tabs.TableTab):
|
||||||
|
table_classes = (VolumePriceTable,)
|
||||||
|
name = _("Volume")
|
||||||
|
slug = "volume"
|
||||||
|
template_name = 'horizon/common/_detail_table.html'
|
||||||
|
|
||||||
|
volume_price_uc = VolumePriceUseCase()
|
||||||
|
|
||||||
|
def get_volume_price_data(self):
|
||||||
|
try:
|
||||||
|
data = self.volume_price_uc.list(self.request)
|
||||||
|
return data
|
||||||
|
except Exception:
|
||||||
|
error_message = _('Unable to get volume prices')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class FloatingIpTab(tabs.TableTab):
|
||||||
|
table_classes = (FloatingIpPriceTable,)
|
||||||
|
name = _("Floating IP")
|
||||||
|
slug = "floating_ip"
|
||||||
|
template_name = 'horizon/common/_detail_table.html'
|
||||||
|
|
||||||
|
fip_price_uc = FloatingIpPriceUseCase()
|
||||||
|
|
||||||
|
def get_floating_ip_price_data(self):
|
||||||
|
try:
|
||||||
|
data = self.fip_price_uc.list(self.request)
|
||||||
|
return data
|
||||||
|
except Exception:
|
||||||
|
error_message = _('Unable to get floating IP prices')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class RouterTab(tabs.TableTab):
|
||||||
|
table_classes = (RouterPriceTable,)
|
||||||
|
name = _("Router")
|
||||||
|
slug = "router"
|
||||||
|
template_name = 'horizon/common/_detail_table.html'
|
||||||
|
|
||||||
|
price_uc = RouterPriceUseCase()
|
||||||
|
|
||||||
|
def get_router_price_data(self):
|
||||||
|
try:
|
||||||
|
data = self.price_uc.list(self.request)
|
||||||
|
return data
|
||||||
|
except Exception:
|
||||||
|
error_message = _('Unable to get router prices')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotTab(tabs.TableTab):
|
||||||
|
table_classes = (SnapshotPriceTable,)
|
||||||
|
name = _("Snapshot")
|
||||||
|
slug = "snapshot"
|
||||||
|
template_name = 'horizon/common/_detail_table.html'
|
||||||
|
|
||||||
|
price_uc = SnapshotPriceUseCase()
|
||||||
|
|
||||||
|
def get_snapshot_price_data(self):
|
||||||
|
try:
|
||||||
|
data = self.price_uc.list(self.request)
|
||||||
|
return data
|
||||||
|
except Exception:
|
||||||
|
error_message = _('Unable to get snapshot prices')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
class ImageTab(tabs.TableTab):
|
||||||
|
table_classes = (ImagePriceTable,)
|
||||||
|
name = _("Image")
|
||||||
|
slug = "image"
|
||||||
|
template_name = 'horizon/common/_detail_table.html'
|
||||||
|
|
||||||
|
price_uc = ImagePriceUseCase()
|
||||||
|
|
||||||
|
def get_image_price_data(self):
|
||||||
|
try:
|
||||||
|
data = self.price_uc.list(self.request)
|
||||||
|
return data
|
||||||
|
except Exception:
|
||||||
|
error_message = _('Unable to get image prices')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class PriceConfigurationTabs(tabs.TabGroup):
|
||||||
|
slug = "price_config"
|
||||||
|
tabs = (FlavorTab, VolumeTab, FloatingIpTab, RouterTab, SnapshotTab, ImageTab, )
|
||||||
|
sticky = True
|
|
@ -0,0 +1,18 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans 'Create/update a flavor price.' %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
{% if cancel_url %}
|
||||||
|
<a href="{% block cancel_url %}{{ cancel_url }}{% endblock %}"
|
||||||
|
class="btn btn-default cancel">
|
||||||
|
{{ cancel_label }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<input class="btn btn-primary" type="submit" disabled value="{{ submit_label }}">
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans 'Create/update a floating IP price for each allocation.' %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
{% if cancel_url %}
|
||||||
|
<a href="{% block cancel_url %}{{ cancel_url }}{% endblock %}"
|
||||||
|
class="btn btn-default cancel">
|
||||||
|
{{ cancel_label }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<input class="btn btn-primary" type="submit" disabled value="{{ submit_label }}">
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans 'Create/update a image price for each 1GB of space.' %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
{% if cancel_url %}
|
||||||
|
<a href="{% block cancel_url %}{{ cancel_url }}{% endblock %}"
|
||||||
|
class="btn btn-default cancel">
|
||||||
|
{{ cancel_label }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<input class="btn btn-primary" type="submit" disabled value="{{ submit_label }}">
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans 'Create/update a router price for each allocation that have external network.' %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
{% if cancel_url %}
|
||||||
|
<a href="{% block cancel_url %}{{ cancel_url }}{% endblock %}"
|
||||||
|
class="btn btn-default cancel">
|
||||||
|
{{ cancel_label }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<input class="btn btn-primary" type="submit" disabled value="{{ submit_label }}">
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans 'Create/update a snapshot price for each 1GB of space.' %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
{% if cancel_url %}
|
||||||
|
<a href="{% block cancel_url %}{{ cancel_url }}{% endblock %}"
|
||||||
|
class="btn btn-default cancel">
|
||||||
|
{{ cancel_label }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<input class="btn btn-primary" type="submit" disabled value="{{ submit_label }}">
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans 'Create/update a volume price for each 1GB of space.' %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
{% if cancel_url %}
|
||||||
|
<a href="{% block cancel_url %}{{ cancel_url }}{% endblock %}"
|
||||||
|
class="btn btn-default cancel">
|
||||||
|
{{ cancel_label }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<input class="btn btn-primary" type="submit" disabled value="{{ submit_label }}">
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}{% trans "Create/Update Flavor Price" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "yuyu_demo/price_configuration_demo/_create_flavor.html" %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}{% trans "Create/Update Floating IP Price" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "yuyu_demo/price_configuration_demo/_create_floating_ip.html" %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}{% trans "Create/Update Image Price" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "yuyu_demo/price_configuration_demo/_create_image.html" %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}{% trans "Create/Update Router Price" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "yuyu_demo/price_configuration_demo/_create_router.html" %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}{% trans "Create/Update Snapshot Price" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "yuyu_demo/price_configuration_demo/_create_snapshot.html" %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}{% trans "Create/Update Volume Price" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "yuyu_demo/price_configuration_demo/_create_volume.html" %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Price Configuration" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "admin/price_configuration/missing_prices.html" %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,70 @@
|
||||||
|
{% if missing_price.flavor %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
Flavor price not complete
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if missing_price.volume %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
Volume price not complete
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if missing_price.fip %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
Floating IP price not complete
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if missing_price.router %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
Router IP price not complete
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if missing_price.snapshot %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
Snapshot price not complete
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if missing_price.image %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
Image price not complete
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
35
yuyu_demo/admin/price_configuration_demo/urls.py
Normal file
35
yuyu_demo/admin/price_configuration_demo/urls.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
url(r'^flavor_price/create/$', views.FlavorPriceAddFormView.as_view(), name='flavor_price_create'),
|
||||||
|
url(r'^flavor_price/update/(?P<id>[^/]+)/$', views.FlavorPriceUpdateFormView.as_view(), name='flavor_price_update'),
|
||||||
|
url(r'^volume_price/create/$', views.VolumePriceAddFormView.as_view(), name='volume_price_create'),
|
||||||
|
url(r'^volume_price/update/(?P<id>[^/]+)/$', views.VolumePriceUpdateFormView.as_view(), name='volume_price_update'),
|
||||||
|
url(r'^floating_ip_price/create/$', views.FloatingIpPriceAddFormView.as_view(), name='floating_ip_price_create'),
|
||||||
|
url(r'^floating_ip_price/update/(?P<id>[^/]+)/$', views.FloatingIpPriceUpdateFormView.as_view(),
|
||||||
|
name='floating_ip_price_update'),
|
||||||
|
url(r'^router_price/create/$', views.RouterPriceAddFormView.as_view(), name='router_price_create'),
|
||||||
|
url(r'^router_price/update/(?P<id>[^/]+)/$', views.RouterPriceUpdateFormView.as_view(),
|
||||||
|
name='router_price_update'),
|
||||||
|
url(r'^snapshot_price/create/$', views.SnapshotPriceAddFormView.as_view(), name='snapshot_price_create'),
|
||||||
|
url(r'^snapshot_price/update/(?P<id>[^/]+)/$', views.SnapshotPriceUpdateFormView.as_view(),
|
||||||
|
name='snapshot_price_update'),
|
||||||
|
url(r'^image_price/create/$', views.ImagePriceAddFormView.as_view(), name='image_price_create'),
|
||||||
|
url(r'^image_price/update/(?P<id>[^/]+)/$', views.ImagePriceUpdateFormView.as_view(),
|
||||||
|
name='image_price_update'),
|
||||||
|
]
|
117
yuyu_demo/admin/price_configuration_demo/views.py
Normal file
117
yuyu_demo/admin/price_configuration_demo/views.py
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.urls import reverse_lazy, reverse
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from neutronclient.common import exceptions as neutron_exc
|
||||||
|
|
||||||
|
|
||||||
|
from .forms import FlavorPriceForm, VolumePriceForm, FloatingIpPriceForm, RouterPriceForm, SnapshotPriceForm, ImagePriceForm
|
||||||
|
from .tabs import PriceConfigurationTabs
|
||||||
|
|
||||||
|
from ....yuyu.admin.price_configuration import views
|
||||||
|
|
||||||
|
class IndexView(views.IndexView):
|
||||||
|
tab_group_class = PriceConfigurationTabs
|
||||||
|
|
||||||
|
|
||||||
|
class FlavorPriceAddFormView(views.FlavorPriceAddFormView):
|
||||||
|
form_class = FlavorPriceForm
|
||||||
|
submit_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:flavor_price_create")
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_flavor.html'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class FlavorPriceUpdateFormView(views.FlavorPriceUpdateFormView):
|
||||||
|
form_class = FlavorPriceForm
|
||||||
|
submit_url = "horizon:yuyu_demo:price_configuration_demo:flavor_price_update"
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_flavor.html'
|
||||||
|
|
||||||
|
|
||||||
|
class VolumePriceAddFormView(views.VolumePriceAddFormView):
|
||||||
|
form_class = VolumePriceForm
|
||||||
|
submit_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:volume_price_create")
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_volume.html'
|
||||||
|
|
||||||
|
|
||||||
|
class VolumePriceUpdateFormView(views.VolumePriceUpdateFormView):
|
||||||
|
form_class = VolumePriceForm
|
||||||
|
form_id = "volume_price_form_update"
|
||||||
|
page_title = _("Volume Price")
|
||||||
|
submit_label = _("Update Volume Price")
|
||||||
|
submit_url = "horizon:yuyu_demo:price_configuration_demo:volume_price_update"
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_volume.html'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class FloatingIpPriceAddFormView(views.FloatingIpPriceAddFormView):
|
||||||
|
form_class = FloatingIpPriceForm
|
||||||
|
|
||||||
|
submit_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:floating_ip_price_create")
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_floating_ip.html'
|
||||||
|
|
||||||
|
|
||||||
|
class FloatingIpPriceUpdateFormView(views.FloatingIpPriceUpdateFormView):
|
||||||
|
form_class = FloatingIpPriceForm
|
||||||
|
submit_url = "horizon:yuyu_demo:price_configuration_demo:floating_ip_price_update"
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_floating_ip.html'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class RouterPriceAddFormView(views.RouterPriceAddFormView):
|
||||||
|
form_class = RouterPriceForm
|
||||||
|
|
||||||
|
submit_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:router_price_create")
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_router.html'
|
||||||
|
|
||||||
|
class RouterPriceUpdateFormView(views.RouterPriceUpdateFormView):
|
||||||
|
form_class = RouterPriceForm
|
||||||
|
submit_url = "horizon:yuyu_demo:price_configuration_demo:router_price_update"
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_router.html'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotPriceAddFormView(views.SnapshotPriceAddFormView):
|
||||||
|
form_class = SnapshotPriceForm
|
||||||
|
submit_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:snapshot_price_create")
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_snapshot.html'
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotPriceUpdateFormView(views.SnapshotPriceUpdateFormView):
|
||||||
|
form_class = SnapshotPriceForm
|
||||||
|
submit_url = "horizon:yuyu_demo:price_configuration_demo:snapshot_price_update"
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_snapshot.html'
|
||||||
|
|
||||||
|
|
||||||
|
class ImagePriceAddFormView(views.ImagePriceAddFormView):
|
||||||
|
form_class = ImagePriceForm
|
||||||
|
submit_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:image_price_create")
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_image.html'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ImagePriceUpdateFormView(views.ImagePriceUpdateFormView):
|
||||||
|
form_class = ImagePriceForm
|
||||||
|
submit_url = "horizon:yuyu_demo:price_configuration_demo:image_price_update"
|
||||||
|
success_url = reverse_lazy("horizon:yuyu_demo:price_configuration_demo:index")
|
||||||
|
template_name = 'yuyu_demo/price_configuration_demo/create_image.html'
|
0
yuyu_demo/admin/projects_balance_demo/__init__.py
Normal file
0
yuyu_demo/admin/projects_balance_demo/__init__.py
Normal file
65
yuyu_demo/admin/projects_balance_demo/forms.py
Normal file
65
yuyu_demo/admin/projects_balance_demo/forms.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import base64
|
||||||
|
|
||||||
|
from django.core import validators
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from djmoney.forms import MoneyField
|
||||||
|
|
||||||
|
from horizon import forms, messages, exceptions
|
||||||
|
from openstack_dashboard.dashboards.yuyu.cases.balance_use_case import BalanceUseCase
|
||||||
|
from openstack_dashboard.dashboards.yuyu.cases.setting_use_case import SettingUseCase
|
||||||
|
|
||||||
|
|
||||||
|
class TopUpForm(forms.SelfHandlingForm):
|
||||||
|
USE_CASE = BalanceUseCase()
|
||||||
|
|
||||||
|
amount = MoneyField(label=_("Amount"), min_value=0, max_digits=10)
|
||||||
|
description = forms.CharField(label=_("Description"))
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
self.project_id = kwargs['project_id']
|
||||||
|
del kwargs['project_id']
|
||||||
|
super().__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
payload = {
|
||||||
|
"amount": data['amount'].amount,
|
||||||
|
"amount_currency": data['amount'].currency.code,
|
||||||
|
'description': data['description'],
|
||||||
|
}
|
||||||
|
|
||||||
|
result = self.USE_CASE.top_up(request, self.project_id, payload)
|
||||||
|
messages.success(request, _(f"Successfully Top Up"))
|
||||||
|
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Unable to top up.'))
|
||||||
|
|
||||||
|
|
||||||
|
class TopDownForm(forms.SelfHandlingForm):
|
||||||
|
USE_CASE = BalanceUseCase()
|
||||||
|
|
||||||
|
amount = MoneyField(label=_("Amount"), min_value=0, max_digits=10)
|
||||||
|
description = forms.CharField(label=_("Description"))
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
self.project_id = kwargs['project_id']
|
||||||
|
del kwargs['project_id']
|
||||||
|
super().__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
payload = {
|
||||||
|
"amount": data['amount'].amount,
|
||||||
|
"amount_currency": data['amount'].currency.code,
|
||||||
|
'description': data['description'],
|
||||||
|
}
|
||||||
|
|
||||||
|
result = self.USE_CASE.top_down(request, self.project_id, payload)
|
||||||
|
messages.success(request, _(f"Successfully Top Down"))
|
||||||
|
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Unable to top down.'))
|
21
yuyu_demo/admin/projects_balance_demo/panel.py
Normal file
21
yuyu_demo/admin/projects_balance_demo/panel.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectsBalanceDemo(horizon.Panel):
|
||||||
|
name = _("Projects Balance")
|
||||||
|
slug = "projects_balance_demo"
|
||||||
|
|
74
yuyu_demo/admin/projects_balance_demo/tables.py
Normal file
74
yuyu_demo/admin/projects_balance_demo/tables.py
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import tables
|
||||||
|
|
||||||
|
|
||||||
|
class DetailAction(tables.LinkAction):
|
||||||
|
name = "detail"
|
||||||
|
verbose_name = "Detail"
|
||||||
|
|
||||||
|
def get_link_url(self, datum=None, ):
|
||||||
|
return reverse("horizon:admin:projects_balance:balance_detail", kwargs={
|
||||||
|
"project_id": datum['project_id'],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class TopUpAction(tables.LinkAction):
|
||||||
|
name = "top_up"
|
||||||
|
verbose_name = "Top Up"
|
||||||
|
icon = "plus"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
def get_link_url(self, datum=None, ):
|
||||||
|
return reverse("horizon:admin:projects_balance:top_up", kwargs={
|
||||||
|
"project_id": self.table.kwargs['project_id'],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class TopDownAction(tables.LinkAction):
|
||||||
|
name = "top_down"
|
||||||
|
verbose_name = "Top Down"
|
||||||
|
icon = "minus"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
def get_link_url(self, datum=None, ):
|
||||||
|
return reverse("horizon:admin:projects_balance:top_down", kwargs={
|
||||||
|
"project_id": self.table.kwargs['project_id'],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceProjectTable(tables.DataTable):
|
||||||
|
project = tables.WrappingColumn('project', verbose_name=_('Project'))
|
||||||
|
amount = tables.WrappingColumn('amount', verbose_name=_('Amount'))
|
||||||
|
|
||||||
|
def get_object_id(self, datum):
|
||||||
|
return datum['id']
|
||||||
|
|
||||||
|
def get_object_display(self, datum):
|
||||||
|
return datum['project']
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "balance_project_table"
|
||||||
|
hidden_title = True
|
||||||
|
verbose_name = _("Project Balance")
|
||||||
|
row_actions = (DetailAction,)
|
||||||
|
|
||||||
|
|
||||||
|
class BalanceTransactionTable(tables.DataTable):
|
||||||
|
date = tables.WrappingColumn('date', verbose_name=_('Date'))
|
||||||
|
amount = tables.WrappingColumn('amount', verbose_name=_('Amount'))
|
||||||
|
action = tables.Column('action', verbose_name=_('Action'))
|
||||||
|
description = tables.Column('description', verbose_name=_('Description'))
|
||||||
|
|
||||||
|
def get_object_id(self, datum):
|
||||||
|
return datum['id']
|
||||||
|
|
||||||
|
def get_object_display(self, datum):
|
||||||
|
return datum['date']
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "balance_table"
|
||||||
|
hidden_title = True
|
||||||
|
verbose_name = _("Balance Transaction")
|
||||||
|
table_actions = (TopUpAction, TopDownAction,)
|
|
@ -0,0 +1,9 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans 'Top down balance for current project' %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans 'Top up balance for current project' %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block title %}{{ page_title }}{% endblock %}
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Project Balance") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{{ table.render }}
|
||||||
|
{% endblock %}
|
||||||
|
{% block js %}
|
||||||
|
{{ block.super }}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block title %}{{ page_title }}{% endblock %}
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=page_title %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<h3>Current Balance: {{ amount }}</h3>
|
||||||
|
{{ table.render }}
|
||||||
|
{% endblock %}
|
||||||
|
{% block js %}
|
||||||
|
{{ block.super }}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}{% trans "Top Up" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "admin/projects_balance/_form_top_down.html" %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}{% trans "Top Up" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "admin/projects_balance/_form_top_up.html" %}
|
||||||
|
{% endblock %}
|
24
yuyu_demo/admin/projects_balance_demo/urls.py
Normal file
24
yuyu_demo/admin/projects_balance_demo/urls.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.yuyu.admin.projects_balance import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
url(r'^detail/(?P<project_id>[^/]+)/$', views.DetailBalanceView.as_view(), name='balance_detail'),
|
||||||
|
url(r'^detail/(?P<project_id>[^/]+)/topup/$',
|
||||||
|
views.TopUpView.as_view(), name='top_up'),
|
||||||
|
url(r'^detail/(?P<project_id>[^/]+)/top_down/$',
|
||||||
|
views.TopDownView.as_view(), name='top_down'),
|
||||||
|
]
|
73
yuyu_demo/admin/projects_balance_demo/views.py
Normal file
73
yuyu_demo/admin/projects_balance_demo/views.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
import dateutil.parser
|
||||||
|
from django.urls import reverse_lazy, reverse
|
||||||
|
from django.utils import formats
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from djmoney.money import Money
|
||||||
|
|
||||||
|
from horizon import exceptions, forms
|
||||||
|
from .forms import TopUpForm, TopDownForm
|
||||||
|
from .tables import BalanceProjectTable, BalanceTransactionTable
|
||||||
|
|
||||||
|
from ....yuyu.admin.projects_balance import views
|
||||||
|
|
||||||
|
class IndexView(views.IndexView):
|
||||||
|
table_class = BalanceProjectTable
|
||||||
|
|
||||||
|
class DetailBalanceView(views.DetailBalanceView):
|
||||||
|
table_class = BalanceTransactionTable
|
||||||
|
|
||||||
|
|
||||||
|
class TopUpView(views.TopDownView):
|
||||||
|
form_class = TopUpForm
|
||||||
|
template_name = 'yuyu_demo/projects_balance_demo/form_top_up.html'
|
||||||
|
|
||||||
|
def get_form_kwargs(self):
|
||||||
|
kwargs = super(TopUpView, self).get_form_kwargs()
|
||||||
|
kwargs['project_id'] = self.kwargs['project_id']
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(TopUpView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse('horizon:yuyu_demo:projects_balance_demo:top_up', kwargs={
|
||||||
|
'project_id': self.kwargs['project_id']
|
||||||
|
})
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('horizon:yuyu_demo:projects_balance_demo:balance_detail', kwargs={
|
||||||
|
'project_id': self.kwargs['project_id']
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class TopDownView(views.TopDownView):
|
||||||
|
form_class = TopDownForm
|
||||||
|
template_name = 'yuyu_demo/projects_balance_demo/form_top_down.html'
|
||||||
|
|
||||||
|
def get_form_kwargs(self):
|
||||||
|
kwargs = super(TopDownView, self).get_form_kwargs()
|
||||||
|
kwargs['project_id'] = self.kwargs['project_id']
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(TopDownView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse('horizon:yuyu_demo:projects_balance_demo:top_down', kwargs={
|
||||||
|
'project_id': self.kwargs['project_id']
|
||||||
|
})
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('horizon:yuyu_demo:projects_balance_demo:balance_detail', kwargs={
|
||||||
|
'project_id': self.kwargs['project_id']
|
||||||
|
})
|
||||||
|
|
0
yuyu_demo/admin/projects_invoice_demo/__init__.py
Normal file
0
yuyu_demo/admin/projects_invoice_demo/__init__.py
Normal file
22
yuyu_demo/admin/projects_invoice_demo/panel.py
Normal file
22
yuyu_demo/admin/projects_invoice_demo/panel.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectsInvoice(horizon.Panel):
|
||||||
|
name = _("Projects Invoice")
|
||||||
|
slug = "projects_invoice"
|
||||||
|
permissions = ('openstack.roles.admin', )
|
||||||
|
|
44
yuyu_demo/admin/projects_invoice_demo/tables.py
Normal file
44
yuyu_demo/admin/projects_invoice_demo/tables.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import tables
|
||||||
|
|
||||||
|
|
||||||
|
class InvoiceAction(tables.LinkAction):
|
||||||
|
name = "invoice"
|
||||||
|
verbose_name = "Invoice"
|
||||||
|
|
||||||
|
def get_link_url(self, datum=None, *args, **kwargs):
|
||||||
|
return reverse("horizon:admin:projects_invoice:invoice_detail", kwargs={
|
||||||
|
"id": datum['id'],
|
||||||
|
"project_id": datum['project_id'],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class UsageCostAction(tables.LinkAction):
|
||||||
|
name = "usage_cost"
|
||||||
|
verbose_name = "Usage Cost"
|
||||||
|
|
||||||
|
def get_link_url(self, datum=None, *args, **kwargs):
|
||||||
|
return reverse("horizon:admin:projects_invoice:usage_cost", kwargs={
|
||||||
|
"id": datum['id'],
|
||||||
|
"project_id": datum['project_id'],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class InvoiceTable(tables.DataTable):
|
||||||
|
date = tables.WrappingColumn('date', verbose_name=_('Date'))
|
||||||
|
state = tables.WrappingColumn('state', verbose_name=_('State'))
|
||||||
|
total = tables.Column('total', verbose_name=_('Total'))
|
||||||
|
|
||||||
|
def get_object_id(self, datum):
|
||||||
|
return datum['id']
|
||||||
|
|
||||||
|
def get_object_display(self, datum):
|
||||||
|
return datum['date']
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "invoice_table"
|
||||||
|
hidden_title = True
|
||||||
|
verbose_name = _("Invoice")
|
||||||
|
row_actions = (InvoiceAction, UsageCostAction)
|
|
@ -0,0 +1,159 @@
|
||||||
|
<style>
|
||||||
|
.invoice {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice h2 {
|
||||||
|
margin-top: 0px;
|
||||||
|
line-height: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice .small {
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice hr {
|
||||||
|
margin-top: 10px;
|
||||||
|
border-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice .table tr.line {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice .table td {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice .identity {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice .identity strong {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
color: #666666;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="invoice">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<!-- BEGIN INVOICE -->
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<div class="grid invoice">
|
||||||
|
<div class="grid-body">
|
||||||
|
<div class="invoice-title">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
{{ setting.company_logo }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<h2>invoice<br>
|
||||||
|
<span class="small">order #{{ invoice.id }}</span></h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<address style="max-width: 30%;">
|
||||||
|
{{ setting.company_name }} <br/>
|
||||||
|
{{ setting.company_address }}
|
||||||
|
</address>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6 text-right">
|
||||||
|
<address>
|
||||||
|
<strong>Invoice Month:</strong><br>
|
||||||
|
{{ invoice.start_date|date:"M Y" }}
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<strong>Issue Date:</strong><br>
|
||||||
|
{{ invoice.start_date|date:"d M Y" }}
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<strong>Invoice State:</strong><br>
|
||||||
|
{{ invoice.state_text }}
|
||||||
|
</address>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h3>ORDER SUMMARY</h3>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr class="line">
|
||||||
|
<td><strong>#</strong></td>
|
||||||
|
<td width="70%"><strong>COMPONENT</strong></td>
|
||||||
|
<td class="text-right"><strong>TOTAL COST</strong></td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>1</td>
|
||||||
|
<td><strong>Instance</strong></td>
|
||||||
|
<td class="text-right">{{ instance_cost }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2</td>
|
||||||
|
<td><strong>Volume</strong></td>
|
||||||
|
<td class="text-right">{{ volume_cost }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>3</td>
|
||||||
|
<td><strong>Floating IP</strong></td>
|
||||||
|
<td class="text-right">{{ fip_cost }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>4</td>
|
||||||
|
<td><strong>Router</strong></td>
|
||||||
|
<td class="text-right">{{ router_cost }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>5</td>
|
||||||
|
<td><strong>Snapshot</strong></td>
|
||||||
|
<td class="text-right">{{ snapshot_cost }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="line">
|
||||||
|
<td>6</td>
|
||||||
|
<td><strong>Image</strong></td>
|
||||||
|
<td class="text-right">{{ image_cost }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" class="text-right"><strong>Subtotal</strong></td>
|
||||||
|
<td class="text-right"><strong>{{ invoice.subtotal_money }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
{% if invoice.state != 1 %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" class="text-right"><strong>Tax</strong></td>
|
||||||
|
<td class="text-right"><strong>{{ invoice.tax_money }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" class="text-right"><strong>Total</strong></td>
|
||||||
|
<td class="text-right"><strong>{{ invoice.total_money }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- END INVOICE -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,77 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block title %}{{ page_title }}{% endblock %}
|
||||||
|
{% block main %}
|
||||||
|
{% if invoice %}
|
||||||
|
{% include 'admin/projects_invoice/manage_invoice_modal.html' with invoice=invoice project_balance_amount=project_balance_amount %}
|
||||||
|
|
||||||
|
<button onclick="javascript:downloadPdf();" class="btn btn-default">Download PDF</button>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<div id="usage_cost">
|
||||||
|
<div>
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>Invoice Month</dt>
|
||||||
|
<dd>{{ invoice.start_date|date:"M Y" }}</dd>
|
||||||
|
<dt>Invoice State</dt>
|
||||||
|
<dd>{{ invoice.state_text }}</dd>
|
||||||
|
<dt>Subtotal</dt>
|
||||||
|
<dd>{{ invoice.subtotal_money }}</dd>
|
||||||
|
{% if invoice.state != 1 %}
|
||||||
|
<dt>Tax</dt>
|
||||||
|
<dd>{{ invoice.tax_money }}</dd>
|
||||||
|
<dt>Total</dt>
|
||||||
|
<dd>{{ invoice.total_money }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="instance-cost">
|
||||||
|
{{ instance_cost_table.render }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="volume-cost">
|
||||||
|
{{ volume_cost_table.render }}
|
||||||
|
</div>
|
||||||
|
<div id="floating-ip-cost">
|
||||||
|
{{ floating_ip_cost_table.render }}
|
||||||
|
</div>
|
||||||
|
<div id="router-cost">
|
||||||
|
{{ router_cost_table.render }}
|
||||||
|
</div>
|
||||||
|
<div id="snapshot-cost">
|
||||||
|
{{ snapshot_cost_table.render }}
|
||||||
|
</div>
|
||||||
|
<div id="image-cost">
|
||||||
|
{{ image_cost_table.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<h1>Billing not enabled or you don't have any usage yet</h1> <br/>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block js %}
|
||||||
|
{{ block.super }}
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"
|
||||||
|
integrity="sha512-GsLlZN/3F2ErC5ifS5QtgpiJtWd43JWSuIgh7mbzZ8zBps+dvLusV+eNQATqgA/HdeKFVgA5v3S/cIrLF7QnIg=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function onInvoiceChange(val) {
|
||||||
|
var search = "?invoice_id=" + val;
|
||||||
|
window.location.href = window.location.protocol + "//" + window.location.host + window.location.pathname + search;
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadPdf() {
|
||||||
|
let opt = {
|
||||||
|
filename: 'usage_cost.pdf',
|
||||||
|
margin: [16, 16],
|
||||||
|
enableLinks: true,
|
||||||
|
image: {type: 'jpeg', quality: 0.98},
|
||||||
|
pagebreak: { mode: 'avoid-all', },
|
||||||
|
jsPDF: {unit: 'mm', format: 'a4', orientation: 'portrait'},
|
||||||
|
}
|
||||||
|
html2pdf().set(opt).from(document.getElementById('usage_cost')).save();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,114 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Usage Cost" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "admin/price_configuration/missing_prices.html" %}
|
||||||
|
{% if invoice %}
|
||||||
|
|
||||||
|
<div id="usage_cost">
|
||||||
|
<div class="row" style="margin-bottom: 15px;">
|
||||||
|
<div class="col-md-6">
|
||||||
|
Invoice Month <b>{{ invoice.start_date|date:"M Y" }}</b>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<span class="pull-right" data-html2canvas-ignore="true">
|
||||||
|
{% include 'admin/projects_invoice/manage_invoice_modal.html' with invoice=invoice project_balance_amount=project_balance_amount %}
|
||||||
|
<button onclick="javascript:downloadPdf();" class="btn btn-default">Download PDF</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">Invoice State</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<h2> {{ invoice.state_text }} </h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">Subtotal</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<h2>{{ invoice.subtotal_money }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if invoice.state != 1 %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">Tax</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<h2> {{ invoice.tax_money }} </h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">Total</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<h2>{{ invoice.total_money }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<h1>Billing not enabled or you don't have any usage yet</h1> <br/>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ block.super }}
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"
|
||||||
|
integrity="sha512-GsLlZN/3F2ErC5ifS5QtgpiJtWd43JWSuIgh7mbzZ8zBps+dvLusV+eNQATqgA/HdeKFVgA5v3S/cIrLF7QnIg=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function downloadPdf() {
|
||||||
|
let opt = {
|
||||||
|
filename: 'usage_cost.pdf',
|
||||||
|
margin: [16, 16],
|
||||||
|
enableLinks: true,
|
||||||
|
image: {type: 'jpeg', quality: 0.98},
|
||||||
|
pagebreak: { mode: 'avoid-all', },
|
||||||
|
jsPDF: {unit: 'mm', format: 'a4', orientation: 'portrait'},
|
||||||
|
}
|
||||||
|
|
||||||
|
// clone element to modify
|
||||||
|
const ucElement = document.getElementById('usage_cost');
|
||||||
|
const ucElementClone = ucElement.cloneNode(true);
|
||||||
|
|
||||||
|
// modify element
|
||||||
|
const navTabs = ucElementClone.querySelector('.nav-tabs');
|
||||||
|
navTabs.style.display = 'none';
|
||||||
|
const tabContent = ucElementClone.querySelectorAll('.tab-pane');
|
||||||
|
tabContent.forEach(content => {
|
||||||
|
content.classList.remove("tab-pane");
|
||||||
|
});
|
||||||
|
|
||||||
|
html2pdf().set(opt).from(ucElementClone).save();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{% load horizon %}
|
||||||
|
{% jstemplate %}
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}
|
||||||
|
{% trans "Price_Volume_Panel" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Price_Volume_Panel") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% endjstemplate %}
|
|
@ -0,0 +1,23 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block title %}{{ page_title }}{% endblock %}
|
||||||
|
{% block main %}
|
||||||
|
<a class="btn btn-default" href="?print=true" target="_blank">Download PDF</a>
|
||||||
|
{% include 'admin/projects_invoice/manage_invoice_modal.html' with invoice=invoice project_balance_amount=project_balance_amount %}
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
{% include 'admin/projects_invoice/base_invoice.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block js %}
|
||||||
|
{{ block.super }}
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"
|
||||||
|
integrity="sha512-GsLlZN/3F2ErC5ifS5QtgpiJtWd43JWSuIgh7mbzZ8zBps+dvLusV+eNQATqgA/HdeKFVgA5v3S/cIrLF7QnIg=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function downloadPdf() {
|
||||||
|
window.print();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Invoice Download</title>
|
||||||
|
{% include "_stylesheets.html" %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% include 'admin/projects_invoice/base_invoice.html' %}
|
||||||
|
{% include "horizon/_scripts.html" %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.print();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,32 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block title %}{{ page_title }}{% endblock %}
|
||||||
|
{% block main %}
|
||||||
|
<div class="row" style="margin-bottom: 15px;">
|
||||||
|
<div class="col-md-6">
|
||||||
|
|
||||||
|
<b>Invoice Month</b>
|
||||||
|
<select id="project_select" onchange="onProjectSelect(this.value)">
|
||||||
|
{% for i in project_list %}
|
||||||
|
<option
|
||||||
|
value='{"project_id": "{{ i.id }}", "project_name": "{{ i.name }}"}'
|
||||||
|
{% if i.id == current_project_id %}selected {% endif %}
|
||||||
|
>{{ i.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ table.render }}
|
||||||
|
{% endblock %}
|
||||||
|
{% block js %}
|
||||||
|
{{ block.super }}
|
||||||
|
<script type="text/javascript">
|
||||||
|
function onProjectSelect(val) {
|
||||||
|
console.log(val)
|
||||||
|
const data = JSON.parse(val);
|
||||||
|
var search = "?project_id=" + data.project_id + "&project_name=" + data.project_name;
|
||||||
|
window.location.href = window.location.protocol + "//" + window.location.host + window.location.pathname + search;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,51 @@
|
||||||
|
{% if invoice.state == 2 %}
|
||||||
|
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#invoice_finish_modal">
|
||||||
|
Set to Finished
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if invoice.state == 100 %}
|
||||||
|
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#invoice_rollback_unpaid_modal">
|
||||||
|
Rollback to Unpaid
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="modal fade" id="invoice_finish_modal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="myModalLabel">Finish Invoice</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
Project Balance: {{ project_balance_amount }}
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<a class="btn btn-warning"
|
||||||
|
href="{% url 'horizon:admin:projects_invoice:finish_invoice' invoice.id %}?next={{ request.path }}&skip_balance=true">Finish without Deduct Balance</a>
|
||||||
|
|
||||||
|
<a class="btn btn-success"
|
||||||
|
href="{% url 'horizon:admin:projects_invoice:finish_invoice' invoice.id %}?next={{ request.path }}">Finish and Deduct Balance</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="invoice_rollback_unpaid_modal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="myModalLabel">Rollback to Unpaid</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
Project Balance: {{ project_balance_amount }}
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<a class="btn btn-danger"
|
||||||
|
href="{% url 'horizon:admin:projects_invoice:rollback_to_unpaid' invoice.id %}?next={{ request.path }}&skip_balance=true">Rollback without Refund Balance</a>
|
||||||
|
|
||||||
|
<a class="btn btn-warning"
|
||||||
|
href="{% url 'horizon:admin:projects_invoice:rollback_to_unpaid' invoice.id %}?next={{ request.path }}">Rollback and Refund Balance</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
25
yuyu_demo/admin/projects_invoice_demo/urls.py
Normal file
25
yuyu_demo/admin/projects_invoice_demo/urls.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.yuyu.admin.projects_invoice import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
url(r'^invoice/detail/(?P<project_id>[^/]+)/(?P<id>[^/]+)/$', views.InvoiceView.as_view(), name='invoice_detail'),
|
||||||
|
url(r'^invoice/usage/(?P<project_id>[^/]+)/(?P<id>[^/]+)/$', views.UsageCostTabView.as_view(), name='usage_cost'),
|
||||||
|
url(r'^invoice/finish/(?P<id>[^/]+)/$', views.FinishInvoice.as_view(), name='finish_invoice'),
|
||||||
|
url(r'^invoice/rollback_to_unpaid/(?P<id>[^/]+)/$', views.RollbackToUnpaidInvoice.as_view(),
|
||||||
|
name='rollback_to_unpaid'),
|
||||||
|
]
|
45
yuyu_demo/admin/projects_invoice_demo/views.py
Normal file
45
yuyu_demo/admin/projects_invoice_demo/views.py
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import views
|
||||||
|
|
||||||
|
from .tables import InvoiceTable
|
||||||
|
|
||||||
|
from ....yuyu.admin.projects_invoice import views
|
||||||
|
|
||||||
|
class IndexView(views.IndexView):
|
||||||
|
table_class = InvoiceTable
|
||||||
|
|
||||||
|
class InvoiceView(views.InvoiceView):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class UsageCostTabView(views.UsageCostTabView):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class UsageCostView(views.UsageCostView):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FinishInvoice(views.FinishInvoice):
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
next_url = request.GET.get('next', reverse('horizon:yuyu_demo:projects_invoice_demo:index'))
|
||||||
|
return HttpResponseRedirect(next_url)
|
||||||
|
|
||||||
|
|
||||||
|
class RollbackToUnpaidInvoice(views.RollbackToUnpaidInvoice):
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
next_url = request.GET.get('next', reverse('horizon:yuyu_demo:projects_invoice_demo:index'))
|
||||||
|
return HttpResponseRedirect(next_url)
|
28
yuyu_demo/dashboard.py
Normal file
28
yuyu_demo/dashboard.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Copyright 2012 Nebula, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from openstack_auth import utils
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
from horizon.utils import settings as utils_settings
|
||||||
|
|
||||||
|
|
||||||
|
class YuyuDemo(horizon.Dashboard):
|
||||||
|
name = _("Admin - Yuyu Demo")
|
||||||
|
slug = "yuyu_demo"
|
||||||
|
default_panel = 'billing_overview_demo'
|
||||||
|
|
||||||
|
|
||||||
|
horizon.register(YuyuDemo)
|
6
yuyu_demo/local/enabled/_6600_yuyu_demo.py
Normal file
6
yuyu_demo/local/enabled/_6600_yuyu_demo.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
ADD_INSTALLED_APPS = [
|
||||||
|
'djmoney',
|
||||||
|
'openstack_dashboard.dashboards.yuyu_demo',
|
||||||
|
]
|
||||||
|
|
||||||
|
DASHBOARD ='yuyu_demo'
|
|
@ -0,0 +1,8 @@
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
# The slug of the panel group to be added to HORIZON_CONFIG. Required.
|
||||||
|
PANEL_GROUP = 'billing'
|
||||||
|
# The display name of the PANEL_GROUP. Required.
|
||||||
|
PANEL_GROUP_NAME = _('Billing')
|
||||||
|
# The slug of the dashboard the PANEL_GROUP associated with. Required.
|
||||||
|
PANEL_GROUP_DASHBOARD = 'yuyu_demo'
|
9
yuyu_demo/local/enabled/_6602_admin_billing_overview.py
Normal file
9
yuyu_demo/local/enabled/_6602_admin_billing_overview.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
||||||
|
PANEL = 'billing_overview_demo'
|
||||||
|
# The slug of the dashboard the PANEL associated with. Required.
|
||||||
|
PANEL_DASHBOARD = 'yuyu_demo'
|
||||||
|
# The slug of the panel group the PANEL is associated with.
|
||||||
|
PANEL_GROUP = 'billing'
|
||||||
|
|
||||||
|
# Python panel class of the PANEL to be added.
|
||||||
|
ADD_PANEL = 'openstack_dashboard.dashboards.yuyu_demo.admin.billing_overview_demo.panel.BillingOverviewDemo'
|
|
@ -0,0 +1,9 @@
|
||||||
|
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
||||||
|
PANEL = 'price_configuration_demo'
|
||||||
|
# The slug of the dashboard the PANEL associated with. Required.
|
||||||
|
PANEL_DASHBOARD = 'yuyu_demo'
|
||||||
|
# The slug of the panel group the PANEL is associated with.
|
||||||
|
PANEL_GROUP = 'billing'
|
||||||
|
|
||||||
|
# Python panel class of the PANEL to be added.
|
||||||
|
ADD_PANEL = 'openstack_dashboard.dashboards.yuyu_demo.admin.price_configuration_demo.panel.PriceConfigurationDemo'
|
9
yuyu_demo/local/enabled/_6604_admin_billing_setting.py
Normal file
9
yuyu_demo/local/enabled/_6604_admin_billing_setting.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
||||||
|
PANEL = 'billing_setting_demo'
|
||||||
|
# The slug of the dashboard the PANEL associated with. Required.
|
||||||
|
PANEL_DASHBOARD = 'yuyu_demo'
|
||||||
|
# The slug of the panel group the PANEL is associated with.
|
||||||
|
PANEL_GROUP = 'billing'
|
||||||
|
|
||||||
|
# Python panel class of the PANEL to be added.
|
||||||
|
ADD_PANEL = 'openstack_dashboard.dashboards.yuyu_demo.admin.billing_setting_demo.panel.BillingSettingDemo'
|
|
@ -0,0 +1,9 @@
|
||||||
|
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
||||||
|
PANEL = 'projects_invoice_demo'
|
||||||
|
# The slug of the dashboard the PANEL associated with. Required.
|
||||||
|
PANEL_DASHBOARD = 'yuyu_demo'
|
||||||
|
# The slug of the panel group the PANEL is associated with.
|
||||||
|
PANEL_GROUP = 'billing'
|
||||||
|
|
||||||
|
# Python panel class of the PANEL to be added.
|
||||||
|
ADD_PANEL = 'openstack_dashboard.dashboards.yuyu_demo.admin.projects_invoice_demo.panel.ProjectsInvoiceDemo'
|
|
@ -0,0 +1,9 @@
|
||||||
|
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
||||||
|
PANEL = 'notification_center_demo'
|
||||||
|
# The slug of the dashboard the PANEL associated with. Required.
|
||||||
|
PANEL_DASHBOARD = 'yuyu_demo'
|
||||||
|
# The slug of the panel group the PANEL is associated with.
|
||||||
|
PANEL_GROUP = 'billing'
|
||||||
|
|
||||||
|
# Python panel class of the PANEL to be added.
|
||||||
|
ADD_PANEL = 'openstack_dashboard.dashboards.yuyu_demo.admin.notification_center_demo.panel.NotificationCenterDemo'
|
|
@ -0,0 +1,9 @@
|
||||||
|
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
||||||
|
PANEL = 'projects_balance_demo'
|
||||||
|
# The slug of the dashboard the PANEL associated with. Required.
|
||||||
|
PANEL_DASHBOARD = 'yuyu_demo'
|
||||||
|
# The slug of the panel group the PANEL is associated with.
|
||||||
|
PANEL_GROUP = 'billing'
|
||||||
|
|
||||||
|
# Python panel class of the PANEL to be added.
|
||||||
|
ADD_PANEL = 'openstack_dashboard.dashboards.yuyu_demo.admin.projects_balance_demo.panel.ProjectsBalanceDemo'
|
Loading…
Add table
Reference in a new issue