Rework admin form/list view
parent
39745971ff
commit
7ad9fa4335
106
formity/admin.py
106
formity/admin.py
|
@ -4,10 +4,11 @@ import datetime
|
||||||
import csv
|
import csv
|
||||||
from flask import redirect, flash, request, url_for, make_response, current_app, session, has_request_context
|
from flask import redirect, flash, request, url_for, make_response, current_app, session, has_request_context
|
||||||
import flask_admin
|
import flask_admin
|
||||||
|
from flask_admin.model.template import macro
|
||||||
import pdfplumber
|
import pdfplumber
|
||||||
from flask_admin.form import rules
|
from flask_admin.form import rules
|
||||||
from formity.extensions import admin, db, ModelView, ModelViewHighSecurity, AdminSecurityMixin
|
from formity.extensions import admin, db, ModelView, ModelViewHighSecurity, AdminSecurityMixin
|
||||||
from wtforms import TextAreaField, validators
|
from wtforms import TextAreaField, RadioField, validators
|
||||||
from formity.models import FaceshieldRequest, RequestChange, Status, PostalCode, ExternalUser, Orga
|
from formity.models import FaceshieldRequest, RequestChange, Status, PostalCode, ExternalUser, Orga
|
||||||
from spaceauth import current_user
|
from spaceauth import current_user
|
||||||
from flask_weasyprint import HTML, render_pdf
|
from flask_weasyprint import HTML, render_pdf
|
||||||
|
@ -50,6 +51,7 @@ class IndexView(AdminSecurityMixin, flask_admin.AdminIndexView):
|
||||||
class FaceshieldRequestAdmin(ModelView):
|
class FaceshieldRequestAdmin(ModelView):
|
||||||
column_default_sort = 'created'
|
column_default_sort = 'created'
|
||||||
details_modal_template = 'changelog_details_modal.html'
|
details_modal_template = 'changelog_details_modal.html'
|
||||||
|
create_template = 'changelog_edit.html'
|
||||||
edit_template = 'changelog_edit.html'
|
edit_template = 'changelog_edit.html'
|
||||||
list_template = 'faceshieldrequest_list.html'
|
list_template = 'faceshieldrequest_list.html'
|
||||||
|
|
||||||
|
@ -75,25 +77,88 @@ class FaceshieldRequestAdmin(ModelView):
|
||||||
'postalcode_info',
|
'postalcode_info',
|
||||||
)
|
)
|
||||||
|
|
||||||
form_create_rules = (
|
form_create_rules = form_edit_rules = (
|
||||||
'entity_info', 'full_name', 'phone_number',
|
rules.Macro('render_submit'),
|
||||||
rules.FieldSet((
|
rules.Container('row', rules.NestedRule([
|
||||||
rules.Field('shipping_name'),
|
rules.Container('split', rules.FieldSet((
|
||||||
rules.Field('shipping_street'),
|
'status',
|
||||||
rules.Field('shipping_postalcode'),
|
'handling_orga',
|
||||||
rules.Field('shipping_city'),
|
'entity_info',
|
||||||
rules.Field('shipping_latitude'),
|
'full_name',
|
||||||
rules.Field('shipping_longitude'),
|
'phone_number',
|
||||||
), 'Shipping information')
|
'email',
|
||||||
|
rules.Macro('render_readonly', name='Extra', field='extra'),
|
||||||
|
'remarks',
|
||||||
|
rules.Macro('render_readonly', name='Created', field='created'),
|
||||||
|
rules.Macro('render_readonly', name='Updated', field='updated'),
|
||||||
|
rules.Macro('render_readonly', name='IP', field='ip'),
|
||||||
|
rules.Macro('render_readonly', name='UA', field='ua'),
|
||||||
|
), 'Request')),
|
||||||
|
rules.Container('split', rules.FieldSet((
|
||||||
|
'delivery_method',
|
||||||
|
'shipping_name',
|
||||||
|
'shipping_street',
|
||||||
|
'shipping_postalcode',
|
||||||
|
'shipping_city',
|
||||||
|
'shipping_latitude',
|
||||||
|
'shipping_longitude',
|
||||||
|
'parent_shipment',
|
||||||
|
'children',
|
||||||
|
'shipping_provider',
|
||||||
|
'shipping_id',
|
||||||
|
), 'Shipping information')),
|
||||||
|
])),
|
||||||
|
rules.Container('split', rules.FieldSet((
|
||||||
|
'faceshield_full_required',
|
||||||
|
'faceshield_front_required',
|
||||||
|
'adapter_3m_dar_required',
|
||||||
|
'adapter_easybreath_dar_required',
|
||||||
|
'adapter_rd40_dar_required',
|
||||||
|
'adapter_secura_dar_required',
|
||||||
|
'faceshield_model',
|
||||||
|
), 'Order')),
|
||||||
|
rules.Container('split', rules.FieldSet((
|
||||||
|
'faceshield_full_delivered',
|
||||||
|
'faceshield_front_delivered',
|
||||||
|
'adapter_3m_dar_delivered',
|
||||||
|
'adapter_easybreath_dar_delivered',
|
||||||
|
'adapter_rd40_dar_delivered',
|
||||||
|
'adapter_secura_dar_delivered',
|
||||||
|
), 'Delivered')),
|
||||||
)
|
)
|
||||||
|
|
||||||
form_overrides = {'entity_info': TextAreaField, 'extra': TextAreaField, 'remarks': TextAreaField}
|
form_choices = {
|
||||||
|
'handling_orga': [
|
||||||
|
('hswaw', 'hswaw'),
|
||||||
|
('hskrk', 'hskrk'),
|
||||||
|
],
|
||||||
|
'delivery_method': [
|
||||||
|
('shipping', 'Shipping'),
|
||||||
|
('pickup', 'Pickup'),
|
||||||
|
],
|
||||||
|
'shipping_provider': [
|
||||||
|
('kurjerzy', 'Kurjerzy'),
|
||||||
|
('xbs', 'XBS Group'),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
form_overrides = {'entity_info': TextAreaField, 'extra': TextAreaField, 'remarks': TextAreaField, 'delivery_method': RadioField}
|
||||||
form_args = {
|
form_args = {
|
||||||
'shipping_name': {'validators': [validators.Length(max=35)]},
|
'shipping_name': {'validators': [validators.Length(max=35)]},
|
||||||
|
'delivery_method': {'choices': form_choices['delivery_method']},
|
||||||
|
}
|
||||||
|
form_widget_args = {
|
||||||
|
'delivery_method': { 'class': 'radio' },
|
||||||
}
|
}
|
||||||
|
|
||||||
form_excluded_columns = ('handling_orga_info', 'changelog', 'postalcode_info')
|
form_excluded_columns = ('handling_orga_info', 'changelog', 'postalcode_info')
|
||||||
|
|
||||||
|
column_list = ('id', 'entity_info', 'full_name', 'items_total_delivered', 'handling_orga', 'created', 'status')
|
||||||
|
column_sortable_list = column_list
|
||||||
|
column_editable_list = ('status', 'remarks', 'handling_orga')
|
||||||
|
|
||||||
|
column_formatters = {'items_total_delivered': macro('render_items')}
|
||||||
|
column_labels = {'items_total_delivered': 'Items'}
|
||||||
|
|
||||||
column_export_list = column_filters
|
column_export_list = column_filters
|
||||||
column_labels = {
|
column_labels = {
|
||||||
'faceshield_front_required': 'Front required',
|
'faceshield_front_required': 'Front required',
|
||||||
|
@ -102,7 +167,6 @@ class FaceshieldRequestAdmin(ModelView):
|
||||||
'faceshield_full_delivered': 'Full delivered',
|
'faceshield_full_delivered': 'Full delivered',
|
||||||
}
|
}
|
||||||
|
|
||||||
column_list = ('id', 'entity_info', 'full_name', 'faceshield_full_required', 'faceshield_full_delivered', 'faceshield_front_required', 'faceshield_front_delivered', 'handling_orga', 'created', 'status')
|
|
||||||
allowed_columns = None
|
allowed_columns = None
|
||||||
extra_allowed_columns = ('id',)
|
extra_allowed_columns = ('id',)
|
||||||
@property
|
@property
|
||||||
|
@ -121,22 +185,6 @@ class FaceshieldRequestAdmin(ModelView):
|
||||||
def _list_columns(self, value):
|
def _list_columns(self, value):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
column_editable_list = ('status', 'remarks', 'handling_orga')
|
|
||||||
form_choices = {
|
|
||||||
'handling_orga': [
|
|
||||||
('hswaw', 'hswaw'),
|
|
||||||
('hskrk', 'hskrk'),
|
|
||||||
],
|
|
||||||
'delivery_method': [
|
|
||||||
('shipping', 'Shipping'),
|
|
||||||
('pickup', 'Pickup'),
|
|
||||||
],
|
|
||||||
'shipping_provider': [
|
|
||||||
('kurjerzy', 'Kurjerzy'),
|
|
||||||
('xbs', 'XBS Group'),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
can_delete = False
|
can_delete = False
|
||||||
can_view_details = True
|
can_view_details = True
|
||||||
details_modal = True
|
details_modal = True
|
||||||
|
|
|
@ -146,6 +146,37 @@ class FaceshieldRequest(db.Model):
|
||||||
return self.faceshield_full_delivered // 150
|
return self.faceshield_full_delivered // 150
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def items(self):
|
||||||
|
item_types = ('faceshield_full', 'faceshield_front', 'adapter_3m_dar', 'adapter_easybreath_dar', 'adapter_rd40_dar', 'adapter_secura_dar')
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'type': item,
|
||||||
|
'required': getattr(self, '{}_required'.format(item)),
|
||||||
|
'delivered': getattr(self, '{}_delivered'.format(item)),
|
||||||
|
}
|
||||||
|
for item in item_types
|
||||||
|
if getattr(self, '{}_required'.format(item)) or getattr(self, '{}_delivered'.format(item))
|
||||||
|
]
|
||||||
|
|
||||||
|
@hybrid_property
|
||||||
|
def items_total_delivered(self):
|
||||||
|
return self.faceshield_full_delivered + \
|
||||||
|
self.faceshield_front_delivered + \
|
||||||
|
self.adapter_3m_dar_delivered + \
|
||||||
|
self.adapter_easybreath_dar_delivered + \
|
||||||
|
self.adapter_rd40_dar_delivered + \
|
||||||
|
self.adapter_secura_dar_delivered
|
||||||
|
|
||||||
|
@hybrid_property
|
||||||
|
def items_total_required(self):
|
||||||
|
return self.faceshield_full_required + \
|
||||||
|
self.faceshield_front_required + \
|
||||||
|
self.adapter_3m_dar_required + \
|
||||||
|
self.adapter_easybreath_dar_required + \
|
||||||
|
self.adapter_rd40_dar_required + \
|
||||||
|
self.adapter_secura_dar_required
|
||||||
|
|
||||||
def fetch_shipping_info(self):
|
def fetch_shipping_info(self):
|
||||||
if self.shipping_provider == 'kurjerzy':
|
if self.shipping_provider == 'kurjerzy':
|
||||||
from shipping.kurjerzy import Kurjerzy
|
from shipping.kurjerzy import Kurjerzy
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
{% from "_changelog.html" import render_changelog %}
|
{% from "_changelog.html" import render_changelog %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
{{ render_changelog(model) }}
|
{% if model is defined %}
|
||||||
|
{{ render_changelog(model) }}
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block navlinks %}
|
{% block navlinks %}
|
||||||
|
@ -19,6 +21,7 @@
|
||||||
<li class="active">
|
<li class="active">
|
||||||
<a href="javascript:void(0)">{{ _gettext('Edit') }}</a>
|
<a href="javascript:void(0)">{{ _gettext('Edit') }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% if model is defined %}
|
||||||
{%- if admin_view.can_view_details -%}
|
{%- if admin_view.can_view_details -%}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ get_url('.details_view', id=request.args.get('id'), url=return_url) }}">{{ _gettext('Details') }}</a>
|
<a href="{{ get_url('.details_view', id=request.args.get('id'), url=return_url) }}">{{ _gettext('Details') }}</a>
|
||||||
|
@ -30,5 +33,33 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('map.index_view', id=model.id) }}" title="Show on map"><span class="glyphicon glyphicon-map-marker"></span> Show on map</a>
|
<a href="{{ url_for('map.index_view', id=model.id) }}" title="Show on map"><span class="glyphicon glyphicon-map-marker"></span> Show on map</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% macro row(form, form_opts={}) %}
|
||||||
|
<div class="row">
|
||||||
|
{{ caller() }}
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro split(form, form_opts={}) %}
|
||||||
|
<div class="col-md-6">
|
||||||
|
{{ caller() }}
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro render_submit() %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="pull-right">
|
||||||
|
<input type="submit" class="btn btn-primary btn-lg" value="{{ _gettext('Save') }}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro render_readonly(form, name, field) %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="" class="col-md-2 control-label">{{ name }}</label>
|
||||||
|
<div class="col-md-10" style="white-space: pre-line;"><div class="checkbox">{% if model is defined %}{{ model[field] }}{% endif %}</div></div>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
|
@ -34,3 +34,19 @@ $(function () {
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% macro render_items(model, column) %}
|
||||||
|
<table class="table" style="margin: 0">
|
||||||
|
{% for item in model.items %}
|
||||||
|
{% set color = {
|
||||||
|
'faceshield_full': 'primary',
|
||||||
|
'faceshield_front': 'info',
|
||||||
|
}.get(item.type, 'warning') %}
|
||||||
|
<tr>
|
||||||
|
<td><span class="label label-{{ color }}">{{ item.type }}</span></td>
|
||||||
|
<td class="text-primary">{{ item.required }}</td>
|
||||||
|
<td class="text-success">{{ item.delivered }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endmacro %}
|
||||||
|
|
Loading…
Reference in New Issue