diff --git a/setup_yuyu.sh b/setup_yuyu.sh index 22a57e8..1e7b551 100755 --- a/setup_yuyu.sh +++ b/setup_yuyu.sh @@ -18,6 +18,7 @@ ln -sf $root/yuyu/local/enabled/_6111_project_billing_panel_group.py $horizon_pa ln -sf $root/yuyu/local/enabled/_6112_project_billing_overview.py $horizon_path/openstack_dashboard/local/enabled/_6112_project_billing_overview.py ln -sf $root/yuyu/local/enabled/_6113_project_billing_usage_cost.py $horizon_path/openstack_dashboard/local/enabled/_6113_project_billing_usage_cost.py ln -sf $root/yuyu/local/enabled/_6114_project_billing_invoice.py $horizon_path/openstack_dashboard/local/enabled/_6114_project_billing_invoice.py +ln -sf $root/yuyu/local/enabled/_6115_project_billing_setting.py $horizon_path/openstack_dashboard/local/enabled/_6115_project_billing_setting.py echo "Symlink Creation Done" echo "Now you can configure and yuyu dashboard" \ No newline at end of file diff --git a/yuyu/admin/billing_setting/forms.py b/yuyu/admin/billing_setting/forms.py new file mode 100644 index 0000000..826ed84 --- /dev/null +++ b/yuyu/admin/billing_setting/forms.py @@ -0,0 +1,37 @@ +from django.utils.translation import ugettext_lazy as _ + +from horizon import forms, messages, exceptions +from openstack_dashboard.dashboards.yuyu.cases.setting_use_case import SettingUseCase + + +class SettingForm(forms.SelfHandlingForm): + NAME = "Settings" + USE_CASE = SettingUseCase() + + company_name = forms.CharField(label=_("COMPANY NAME"), + required=False) + company_logo = forms.URLField(label=_("COMPANY LOGO URL"), + required=False) + company_address = forms.CharField(label=_("COMPANY ADDRESS"), + required=False) + email_admin = forms.EmailField(label=_("EMAIL ADMIN"), + required=True) + + invoice_tax = forms.IntegerField(label=_("INVOICE TAX (%)"), + required=True) + + def handle(self, request, data): + try: + result = "" + for k, v in data.items(): + result = self.USE_CASE.set_setting( + request=request, + key=k, + value=v + ) + messages.success(request, _(f"Successfully update {self.NAME}")) + + return result + except Exception as e: + exceptions.handle(request, + _('Unable to update.')) diff --git a/yuyu/admin/billing_setting/tables.py b/yuyu/admin/billing_setting/tables.py new file mode 100644 index 0000000..03e0110 --- /dev/null +++ b/yuyu/admin/billing_setting/tables.py @@ -0,0 +1,11 @@ +from openstack_dashboard.dashboards.yuyu.core.billing_setting.tables import BaseUpdateSettingAction, BaseSettingTable + + +class UpdateSettingAction(BaseUpdateSettingAction): + url = "horizon:admin:billing_setting:update_setting" + + +class SettingTable(BaseSettingTable): + class Meta(object): + table_actions = (UpdateSettingAction,) + diff --git a/yuyu/admin/billing_setting/templates/billing_setting/_form_setting.html b/yuyu/admin/billing_setting/templates/billing_setting/_form_setting.html new file mode 100644 index 0000000..f732ba8 --- /dev/null +++ b/yuyu/admin/billing_setting/templates/billing_setting/_form_setting.html @@ -0,0 +1,8 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block modal-body-right %} +

{% trans "Description:" %}

+

{% trans 'Update a billing setting.' %}

+{% endblock %} + diff --git a/yuyu/admin/billing_setting/templates/billing_setting/form_setting.html b/yuyu/admin/billing_setting/templates/billing_setting/form_setting.html new file mode 100644 index 0000000..83d85d6 --- /dev/null +++ b/yuyu/admin/billing_setting/templates/billing_setting/form_setting.html @@ -0,0 +1,8 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %}{% trans "Update Billing Setting" %}{% endblock %} + +{% block main %} + {% include "admin/billing_setting/_form_setting.html" %} +{% endblock %} diff --git a/yuyu/admin/billing_setting/templates/billing_setting/index.html b/yuyu/admin/billing_setting/templates/billing_setting/index.html index f680740..2bf1611 100644 --- a/yuyu/admin/billing_setting/templates/billing_setting/index.html +++ b/yuyu/admin/billing_setting/templates/billing_setting/index.html @@ -4,6 +4,14 @@ {% block main %} {% include "admin/price_configuration/missing_prices.html" %} + {% include "admin/billing_setting/missing_billing_setting.html" %} + + {# Form #} +
+
+ {{ table.render }} +
+
@@ -13,8 +21,7 @@ {% else %}

Billing Disabled


Please make sure all price is already configured before enable billing

- - Enable + Enable Reset Billing Data {% endif %}
diff --git a/yuyu/admin/billing_setting/templates/billing_setting/missing_billing_setting.html b/yuyu/admin/billing_setting/templates/billing_setting/missing_billing_setting.html new file mode 100644 index 0000000..9281ae3 --- /dev/null +++ b/yuyu/admin/billing_setting/templates/billing_setting/missing_billing_setting.html @@ -0,0 +1,38 @@ +{% if missing_setting.invoice_tax %} +
+
+ +
+
+{% endif %} + +{% if missing_setting.email_notification %} +
+
+ +
+
+{% endif %} + + +{% if missing_setting.email_admin %} +
+
+ +
+
+{% endif %} + + + + + diff --git a/yuyu/admin/billing_setting/urls.py b/yuyu/admin/billing_setting/urls.py index af25ef3..52e9526 100644 --- a/yuyu/admin/billing_setting/urls.py +++ b/yuyu/admin/billing_setting/urls.py @@ -19,5 +19,7 @@ urlpatterns = [ 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'), ] diff --git a/yuyu/admin/billing_setting/views.py b/yuyu/admin/billing_setting/views.py index 797cd4f..b041315 100644 --- a/yuyu/admin/billing_setting/views.py +++ b/yuyu/admin/billing_setting/views.py @@ -10,27 +10,70 @@ # License for the specific language governing permissions and limitations # under the License. from django import shortcuts +from django.urls import reverse_lazy from django.utils.translation import ugettext_lazy as _ -from horizon import views, exceptions, messages +from horizon import views, exceptions, messages, tables, forms from openstack_dashboard.dashboards.yuyu.cases.invoice_use_case import InvoiceUseCase from openstack_dashboard.dashboards.yuyu.cases.setting_use_case import SettingUseCase from openstack_dashboard.dashboards.yuyu.core.utils.price_checker import has_missing_price +from .forms import SettingForm +from .tables import SettingTable -class IndexView(views.APIView): +class IndexView(tables.DataTableView): page_title = _("Setting") template_name = "admin/billing_setting/index.html" + table_class = SettingTable setting_uc = SettingUseCase() + def get_data(self): + try: + setting_uc = self.setting_uc.get_setting_admin(self.request) + + except Exception: + setting_uc = [] + exceptions.handle(self.request, + _("Unable to retrieve data.")) + return setting_uc + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) + + if hasattr(self, "table"): + context[self.context_object_name] = self.table + context['setting'] = self.setting_uc.get_settings(self.request) context['missing_price'] = has_missing_price(self.request) + context['missing_setting'] = self.setting_uc.has_missing_setting(self.request) return context +class UpdateSettingView(forms.ModalFormView): + form_class = SettingForm + form_id = "setting_form_update" + modal_id = "update_setting_modal" + modal_header = _("Update Setting") + page_title = _("Setting") + submit_label = _("Update Setting") + submit_url = reverse_lazy("horizon:admin:billing_setting:update_setting") + success_url = reverse_lazy("horizon:admin:billing_setting:index") + template_name = 'admin/billing_setting/form_setting.html' + + setting_uc = SettingUseCase() + + def get_initial(self): + try: + setting_uc = dict(self.setting_uc.get_setting_admin(self.request)) + except Exception: + setting_uc = None + exceptions.handle(self.request, + _("Unable to retrieve setting.")) + + return setting_uc + + class EnableBillingView(views.APIView): invoice_uc = InvoiceUseCase() diff --git a/yuyu/cases/project_overview_use_case.py b/yuyu/cases/project_overview_use_case.py index 8f4d312..88a88ba 100644 --- a/yuyu/cases/project_overview_use_case.py +++ b/yuyu/cases/project_overview_use_case.py @@ -2,6 +2,15 @@ from openstack_dashboard.dashboards.yuyu.core import yuyu_client class ProjectOverviewUseCase: + def get_tenant(self, request): + response = yuyu_client.get(request, f"project_overview/{request.user.tenant_id}/get_tenant/") + keys_to_include = ['email_notification', ] + + return [x for x in response.json().items() if x[0] in keys_to_include] + + def update_email(self, request, payload): + return yuyu_client.post(request, f"project_overview/{request.user.tenant_id}/update_email/", payload).json() + def total_resource(self, request): response = yuyu_client.get(request, f"project_overview/total_resource/?tenant_id={request.user.tenant_id}") return response.json() diff --git a/yuyu/cases/setting_use_case.py b/yuyu/cases/setting_use_case.py index d218980..7e8fa17 100644 --- a/yuyu/cases/setting_use_case.py +++ b/yuyu/cases/setting_use_case.py @@ -2,10 +2,32 @@ from openstack_dashboard.dashboards.yuyu.core import yuyu_client class SettingUseCase: + def get_settings(self, request): - return yuyu_client.get(request, "settings/").json() + response = yuyu_client.get(request, "settings/").json() + return response def set_setting(self, request, key, value): return yuyu_client.patch(request, f"settings/{key}/", { "value": value }).json() + + def get_setting_admin(self, request): + keys_to_exclude = ['billing_enabled', + 'email_notification'] + response = self.get_settings(request) + + return [x for x in response.items() if x[0] not in keys_to_exclude] + + def has_missing_setting(self, request): + missing = [None, ''] + response = self.get_settings(request) + context = {x[0]: True for x in response.items() if x[1] in missing} + + if context: + context['has_missing'] = True + return context + + context['has_missing'] = True + + return context diff --git a/yuyu/core/billing_setting/tables.py b/yuyu/core/billing_setting/tables.py new file mode 100644 index 0000000..3974658 --- /dev/null +++ b/yuyu/core/billing_setting/tables.py @@ -0,0 +1,48 @@ +from django.urls import reverse +from django.utils.translation import ugettext_lazy as _ + +from horizon import tables + + +class SettingName: + SETTING_NAMES = { + "billing_enabled": _("Billing Enabled"), + "invoice_tax": _("Invoice Tax"), + "company_name": _("Company Name"), + "company_logo": _("Company Logo"), + "company_address": _("Company Address"), + "email_admin": _("Email Admin"), + "email_notification": _("Email Notification") + } + + def get_setting_name(self, setting): + return self.SETTING_NAMES.get(setting[0], setting[0].replace("_", " ").title()) + + def get_setting_value(self, setting): + return setting[1] + + +class BaseUpdateSettingAction(tables.LinkAction): + name = "update_setting" + verbose_name = _("Update Setting") + url = None + classes = ("ajax-modal",) + icon = "pencil" + step = None + + def get_link_url(self, datum=None): + return reverse(self.url) + + +class BaseSettingTable(tables.DataTable): + setting_name = SettingName() + name = tables.Column(setting_name.get_setting_name, verbose_name=_('Setting Name')) + value = tables.Column(setting_name.get_setting_value, verbose_name=_('Value')) + + def get_object_id(self, obj): + return obj + + class Meta(object): + name = "settings" + verbose_name = _("Settings") + multi_select = False diff --git a/yuyu/local/enabled/_6115_project_billing_setting.py b/yuyu/local/enabled/_6115_project_billing_setting.py new file mode 100644 index 0000000..d2836d7 --- /dev/null +++ b/yuyu/local/enabled/_6115_project_billing_setting.py @@ -0,0 +1,10 @@ +# The slug of the panel to be added to HORIZON_CONFIG. Required. +PANEL = 'billing_setting' +# The slug of the dashboard the PANEL associated with. Required. +PANEL_DASHBOARD = 'project' +# 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.project.billing_setting.panel.BillingSetting' +# ADD_PANEL = 'openstack_dashboard.dashboards.yuyu.project.invoice.panel.Invoice' diff --git a/yuyu/project/billing_setting/__init__.py b/yuyu/project/billing_setting/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/yuyu/project/billing_setting/forms.py b/yuyu/project/billing_setting/forms.py new file mode 100644 index 0000000..0c8d305 --- /dev/null +++ b/yuyu/project/billing_setting/forms.py @@ -0,0 +1,26 @@ +from django.utils.translation import ugettext_lazy as _ + +from horizon import forms, messages, exceptions +from openstack_dashboard.dashboards.yuyu.cases.project_overview_use_case import ProjectOverviewUseCase + + +class SettingForm(forms.SelfHandlingForm): + NAME = "Settings" + USE_CASE = ProjectOverviewUseCase() + + email_notification = forms.EmailField(label=_("EMAIL NOTIFICATION"), + required=True) + + def handle(self, request, data): + try: + print(data) + result = self.USE_CASE.update_email( + request=request, + payload=data + ) + messages.success(request, _(f"Successfully update {self.NAME}")) + + return result + except Exception as e: + exceptions.handle(request, + _('Unable to update.')) diff --git a/yuyu/project/billing_setting/panel.py b/yuyu/project/billing_setting/panel.py new file mode 100644 index 0000000..f126d90 --- /dev/null +++ b/yuyu/project/billing_setting/panel.py @@ -0,0 +1,20 @@ +# 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 BillingSetting(horizon.Panel): + name = _("Billing Setting") + slug = "billing_setting" diff --git a/yuyu/project/billing_setting/tables.py b/yuyu/project/billing_setting/tables.py new file mode 100644 index 0000000..a3fe90c --- /dev/null +++ b/yuyu/project/billing_setting/tables.py @@ -0,0 +1,10 @@ +from openstack_dashboard.dashboards.yuyu.core.billing_setting.tables import BaseSettingTable, BaseUpdateSettingAction + + +class UpdateSettingAction(BaseUpdateSettingAction): + url = "horizon:project:billing_setting:update_setting" + + +class SettingTable(BaseSettingTable): + class Meta(object): + table_actions = (UpdateSettingAction,) diff --git a/yuyu/project/billing_setting/templates/billing_setting/_form_setting.html b/yuyu/project/billing_setting/templates/billing_setting/_form_setting.html new file mode 100644 index 0000000..f732ba8 --- /dev/null +++ b/yuyu/project/billing_setting/templates/billing_setting/_form_setting.html @@ -0,0 +1,8 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block modal-body-right %} +

{% trans "Description:" %}

+

{% trans 'Update a billing setting.' %}

+{% endblock %} + diff --git a/yuyu/project/billing_setting/templates/billing_setting/form_setting.html b/yuyu/project/billing_setting/templates/billing_setting/form_setting.html new file mode 100644 index 0000000..e03062e --- /dev/null +++ b/yuyu/project/billing_setting/templates/billing_setting/form_setting.html @@ -0,0 +1,8 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %}{% trans "Create/Update Volume Price" %}{% endblock %} + +{% block main %} + {% include "project/billing_setting/_form_setting.html" %} +{% endblock %} diff --git a/yuyu/project/billing_setting/templates/billing_setting/index.html b/yuyu/project/billing_setting/templates/billing_setting/index.html new file mode 100644 index 0000000..6418351 --- /dev/null +++ b/yuyu/project/billing_setting/templates/billing_setting/index.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Billing Setting" %}{% endblock %} + +{% block main %} + {# Form #} +
+
+ {{ table.render }} +
+
+{% endblock %} diff --git a/yuyu/project/billing_setting/urls.py b/yuyu/project/billing_setting/urls.py new file mode 100644 index 0000000..796dca4 --- /dev/null +++ b/yuyu/project/billing_setting/urls.py @@ -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.conf.urls import url + +from . import views + +urlpatterns = [ + url(r'^$', views.IndexView.as_view(), name='index'), + url(r'^update_setting/$', + views.UpdateSettingView.as_view(), name='update_setting'), +] + diff --git a/yuyu/project/billing_setting/views.py b/yuyu/project/billing_setting/views.py new file mode 100644 index 0000000..ab67525 --- /dev/null +++ b/yuyu/project/billing_setting/views.py @@ -0,0 +1,62 @@ +# 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 django.urls import reverse_lazy, reverse +from django.utils.translation import ugettext_lazy as _ + +from horizon import views, exceptions, messages, tables, forms +from openstack_dashboard.dashboards.yuyu.cases.setting_use_case import SettingUseCase +from .forms import SettingForm +from .tables import SettingTable +from ...cases.project_overview_use_case import ProjectOverviewUseCase + + +class IndexView(tables.DataTableView): + page_title = _("Setting") + template_name = "project/billing_setting/index.html" + table_class = SettingTable + + setting_uc = ProjectOverviewUseCase() + + def get_data(self): + try: + setting_uc = self.setting_uc.get_tenant(self.request) + + except Exception: + setting_uc = [] + exceptions.handle(self.request, + _("Unable to retrieve data.")) + return setting_uc + + +class UpdateSettingView(forms.ModalFormView): + form_class = SettingForm + form_id = "setting_form_update" + modal_id = "update_setting_modal" + modal_header = _("Update Setting") + page_title = _("Setting") + submit_label = _("Update Setting") + submit_url = reverse_lazy("horizon:project:billing_setting:update_setting") + success_url = reverse_lazy("horizon:project:billing_setting:index") + template_name = 'project/billing_setting/form_setting.html' + + setting_uc = ProjectOverviewUseCase() + + def get_initial(self): + try: + setting_uc = dict(self.setting_uc.get_tenant(self.request)) + except Exception: + setting_uc = None + exceptions.handle(self.request, + _("Unable to retrieve setting.")) + + return setting_uc