Rework admin form/list view

master
informatic 2020-04-28 19:58:31 +02:00
parent 39745971ff
commit 7ad9fa4335
4 changed files with 157 additions and 31 deletions

View File

@ -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

View File

@ -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

View File

@ -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 %}

View File

@ -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 %}