
33 changed files with 665 additions and 88 deletions
@ -0,0 +1,195 @@
@@ -0,0 +1,195 @@
|
||||
""" Schemas for form input and validation """ |
||||
|
||||
import deform |
||||
import colander |
||||
|
||||
from .base import CSRFSchema |
||||
from ..models import UserRole, OrderStatus, OrderCategory |
||||
|
||||
CATEGORIES = [(c.name, c.name.capitalize()) for c in OrderCategory] |
||||
STATI = [(s.name, s.name.capitalize()) for s in OrderStatus] |
||||
|
||||
|
||||
class OrderStatus(colander.Schema): |
||||
""" schema for editing order status |
||||
|
||||
parital schema, used in EditOrderSchema |
||||
""" |
||||
|
||||
status = colander.SchemaNode( |
||||
colander.String(), |
||||
widget=deform.widget.SelectWidget( |
||||
values=STATI, |
||||
css_class="custom-select col-sm-9", |
||||
item_css_class="row", |
||||
label_css_class="col-sm-3 col-form-label", |
||||
), |
||||
) |
||||
|
||||
|
||||
class OrderItem(colander.Schema): |
||||
""" schema for editing order information |
||||
|
||||
parital schema, used in NewOrderSchema and EditOrderSchema |
||||
""" |
||||
|
||||
cas_description = colander.SchemaNode( |
||||
colander.String(), |
||||
widget=deform.widget.TextInputWidget( |
||||
item_css_class="row", |
||||
label_css_class="col-sm-3 col-form-label o3-form-copy", |
||||
css_class="col-sm-9", |
||||
), |
||||
) |
||||
category = colander.SchemaNode( |
||||
colander.String(), |
||||
widget=deform.widget.SelectWidget( |
||||
values=CATEGORIES, |
||||
css_class="custom-select col-sm-9", |
||||
item_css_class="row", |
||||
label_css_class="col-sm-3 col-form-label", |
||||
), |
||||
) |
||||
catalog_nr = colander.SchemaNode( |
||||
colander.String(), |
||||
widget=deform.widget.TextInputWidget( |
||||
item_css_class="row", |
||||
label_css_class="col-sm-3 col-form-label o3-form-copy", |
||||
css_class="col-sm-9", |
||||
), |
||||
) |
||||
vendor = colander.SchemaNode( |
||||
colander.String(), |
||||
widget=deform.widget.TextInputWidget( |
||||
item_css_class="row", |
||||
label_css_class="col-sm-3 col-form-label o3-form-copy", |
||||
css_class="col-sm-9", |
||||
), |
||||
) |
||||
package_size = colander.SchemaNode( |
||||
colander.String(), |
||||
widget=deform.widget.TextInputWidget( |
||||
item_css_class="row", |
||||
label_css_class="col-sm-3 col-form-label o3-form-copy", |
||||
css_class="col-sm-9", |
||||
), |
||||
) |
||||
|
||||
|
||||
class MoneyInputSchema(colander.Schema): |
||||
""" custom schema for structured money and currency input """ |
||||
|
||||
amount = colander.SchemaNode( |
||||
colander.Decimal(), |
||||
widget=deform.widget.MoneyInputWidget( |
||||
readonly_template="textinput_disabled.pt", |
||||
css_class="moneyinput amount", |
||||
col_css_class="col-sm-7", |
||||
), |
||||
) |
||||
currency = colander.SchemaNode( |
||||
colander.String(), |
||||
default="EUR", |
||||
widget=deform.widget.TextInputWidget( |
||||
readonly_template="textinput_disabled.pt", |
||||
css_class="moneyinput currency", |
||||
col_css_class="col-sm-2", |
||||
), |
||||
) |
||||
|
||||
def __init__(self, *args, **kwargs): |
||||
""" define the custom schema templates """ |
||||
if "widget" not in kwargs: |
||||
readonly = kwargs.pop("readonly", False) |
||||
kwargs["widget"] = deform.widget.MappingWidget( |
||||
category="default", |
||||
template="money_mapping.pt", |
||||
readonly_template="money_mapping_disabled.pt", |
||||
item_template="money_mapping_item.pt", |
||||
item_readonly_template="money_mapping_item_diabled.pt", |
||||
readonly=readonly, |
||||
label_css_class="col-sm-3 col-form-label o3-form-copy", |
||||
item_css_class="row", |
||||
) |
||||
super().__init__(*args, **kwargs) |
||||
|
||||
|
||||
class OrderPricing(colander.Schema): |
||||
""" schema for editing price information |
||||
|
||||
parital schema, used in NewOrderSchema and EditOrderSchema |
||||
""" |
||||
|
||||
quantity = colander.SchemaNode( |
||||
colander.Integer(), |
||||
validator=colander.Range(min=1), |
||||
widget=deform.widget.TextInputWidget( |
||||
css_class="number col-sm-9", |
||||
item_css_class="row", |
||||
label_css_class="col-sm-3 col-form-label o3-form-copy", |
||||
), |
||||
default=1, |
||||
) |
||||
unit_price = MoneyInputSchema( |
||||
readonly=False, label_css_class="col-sm-3 col-form-label o3-form-copy" |
||||
) |
||||
total_price = MoneyInputSchema( |
||||
readonly=True, label_css_class="col-sm-3 col-form-label o3-form-copy" |
||||
) |
||||
|
||||
|
||||
class OrderOptionals(colander.Schema): |
||||
""" schema for editing optional information |
||||
|
||||
parital schema, used in NewOrderSchema and EditOrderSchema |
||||
""" |
||||
|
||||
account = colander.SchemaNode( |
||||
colander.String(), |
||||
required=False, |
||||
missing="", |
||||
widget=deform.widget.TextInputWidget( |
||||
item_css_class="row", |
||||
label_css_class="col-sm-3 col-form-label o3-form-copy", |
||||
css_class="col-sm-9", |
||||
), |
||||
) |
||||
comment = colander.SchemaNode( |
||||
colander.String(), |
||||
missing="", |
||||
widget=deform.widget.TextAreaWidget( |
||||
rows=7, |
||||
item_css_class="row", |
||||
label_css_class="col-sm-3 col-form-label o3-form-copy", |
||||
css_class="col-sm-9", |
||||
), |
||||
) |
||||
|
||||
|
||||
class EditOrderSchema(CSRFSchema): |
||||
""" edit an order """ |
||||
|
||||
status = OrderStatus() |
||||
item = OrderItem() |
||||
pricing = OrderPricing() |
||||
optional = OrderOptionals() |
||||
|
||||
@classmethod |
||||
def as_form(cls, request, **override): |
||||
""" returns the schema as a form """ |
||||
settings = { |
||||
"buttons": ("Save Changes", "Cancel"), |
||||
"css_class": "deform o3-col-form", |
||||
} |
||||
settings.update(override) |
||||
form = super().as_form(request, **settings) |
||||
|
||||
# disable the status field, if the current user is not a purchaser |
||||
if UserRole.PURCHASER.principal not in request.user.principals: |
||||
form["status"]["status"].widget = deform.widget.TextInputWidget( |
||||
template="textinput_disabled.pt", |
||||
item_css_class="row", |
||||
label_css_class="col-sm-3 col-form-label", |
||||
css_class="col-sm-9", |
||||
) |
||||
return form |
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
<span tal:define="error_class error_class|field.widget.error_class; |
||||
description description|field.description; |
||||
title title|field.title; |
||||
hidden hidden|field.widget.hidden; |
||||
category category|field.widget.category; |
||||
item_template item_template|field.widget.item_template; |
||||
amount_field field.children[0]; |
||||
currency_field field.children[1]; |
||||
oid oid|amount_field.oid; |
||||
required required|amount_field.required; |
||||
label_css_class amount_field.widget.label_css_class|'';" |
||||
i18n:domain="deform" |
||||
class="moneyinput" |
||||
tal:omit-tag> |
||||
|
||||
${field.start_mapping()} |
||||
<div tal:repeat="child field.children" |
||||
tal:replace="structure child.render_template(item_template)" > |
||||
</div> |
||||
${field.end_mapping()} |
||||
|
||||
<p class="help-inline" |
||||
tal:define="errstr 'error-%s' % field.oid" |
||||
tal:repeat="msg amount_field.error.messages()|currency_field.error.messages()" |
||||
i18n:translate="" |
||||
tal:attributes="id repeat.msg.index==0 and errstr or |
||||
('%s-%s' % (errstr, repeat.msg.index))" |
||||
tal:condition="(amount_field.error or currency_field.error) and not field.widget.hidden"> |
||||
${msg} |
||||
</p> |
||||
|
||||
<p tal:condition="field.description and not field.widget.hidden" |
||||
class="help-inline" > |
||||
${field.description} |
||||
</p> |
||||
|
||||
</span> |
||||
|
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
<span tal:define="error_class error_class|field.widget.error_class; |
||||
description description|field.description; |
||||
title title|field.title; |
||||
hidden hidden|field.widget.hidden; |
||||
category category|field.widget.category; |
||||
item_template item_template|field.widget.item_readonly_template; |
||||
amount_field field.children[0]; |
||||
currency_field field.children[1]; |
||||
oid oid|amount_field.oid; |
||||
required required|amount_field.required; |
||||
label_css_class amount_field.widget.label_css_class|'';" |
||||
i18n:domain="deform" |
||||
class="moneyinput" |
||||
tal:omit-tag> |
||||
|
||||
${field.start_mapping()} |
||||
<div tal:repeat="child field.children" |
||||
tal:replace="structure child.render_template(item_template)" > |
||||
</div> |
||||
${field.end_mapping()} |
||||
|
||||
<p class="help-inline" |
||||
tal:define="errstr 'error-%s' % field.oid" |
||||
tal:repeat="msg amount_field.error.messages()|currency_field.error.messages()" |
||||
i18n:translate="" |
||||
tal:attributes="id repeat.msg.index==0 and errstr or |
||||
('%s-%s' % (errstr, repeat.msg.index))" |
||||
tal:condition="(amount_field.error or currency_field.error) and not field.widget.hidden"> |
||||
${msg} |
||||
</p> |
||||
|
||||
<p tal:condition="field.description and not field.widget.hidden" |
||||
class="help-inline" > |
||||
${field.description} |
||||
</p> |
||||
|
||||
</span> |
||||
|
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
<span tal:define="error_class error_class|field.widget.error_class; |
||||
description description|field.description; |
||||
title title|field.title; |
||||
oid oid|field.oid; |
||||
hidden hidden|field.widget.hidden; |
||||
category category|field.widget.category; |
||||
structural hidden or category == 'structural'; |
||||
required required|field.required; |
||||
label_css_class label_css_class|field.widget.label_css_class|'';" |
||||
class="${field.error and 'error' or ''} ${field.widget.col_css_class or ''} ${field.default_item_css_class()}" |
||||
title="${description}" |
||||
id="item-${oid}" |
||||
tal:omit-tag="structural" |
||||
i18n:domain="deform"> |
||||
|
||||
<div tal:define="input_prepend field.widget.input_prepend | None; |
||||
input_append field.widget.input_append | None" |
||||
tal:omit-tag="not (input_prepend or input_append)" |
||||
class="input-group"> |
||||
<span class="input-group-addon" |
||||
tal:condition="input_prepend">${input_prepend}</span |
||||
><span tal:replace="structure field.serialize(cstruct).strip()" |
||||
/><span class="input-group-addon" |
||||
tal:condition="input_append">${input_append}</span> |
||||
</div> |
||||
</span> |
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
<span tal:define="error_class error_class|field.widget.error_class; |
||||
description description|field.description; |
||||
title title|field.title; |
||||
oid oid|field.oid; |
||||
hidden hidden|field.widget.hidden; |
||||
category category|field.widget.category; |
||||
structural hidden or category == 'structural'; |
||||
required required|field.required; |
||||
label_css_class label_css_class|field.widget.label_css_class|'';" |
||||
class="${field.error and 'error' or ''} ${field.widget.col_css_class or ''} ${field.default_item_css_class()}" |
||||
title="${description}" |
||||
id="item-${oid}" |
||||
tal:omit-tag="structural" |
||||
i18n:domain="deform"> |
||||
|
||||
<div tal:define="input_prepend field.widget.input_prepend | None; |
||||
input_append field.widget.input_append | None" |
||||
tal:omit-tag="not (input_prepend or input_append)" |
||||
class="input-group"> |
||||
<span class="input-group-addon" |
||||
tal:condition="input_prepend">${input_prepend}</span |
||||
><span tal:replace="structure field.serialize(cstruct, readonly=True).strip()" |
||||
/><span class="input-group-addon" |
||||
tal:condition="input_append">${input_append}</span> |
||||
</div> |
||||
</span> |
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
{% extends "ordr3:templates/layout_full.jinja2" %} |
||||
|
||||
{% block subtitle %} Edit Order {{ context.model.cas_description }} {% endblock subtitle %} |
||||
|
||||
{% block content %} |
||||
|
||||
<div class="col-5"> |
||||
<h4 class="mb-2 text-muted mb-4 text-truncate">Edit Order <span class="text-dark">{{ context.model.cas_description }}</span></h4> |
||||
{{form.render()|safe}} |
||||
<hr> |
||||
<p class="mt-4"> |
||||
{% if request.has_permission("add", context.__parent__) %} |
||||
<a href="{{ context|resource_url('reorder') }}" class="btn btn-outline-primary">Reorder Item</a> |
||||
{% endif %} |
||||
{% if request.has_permission("delete", context) %} |
||||
<a href="{{ context|resource_url('delete') }}" class="btn btn-outline-danger">Delete Order</a> |
||||
{% endif %} |
||||
</p> |
||||
</div> |
||||
|
||||
<div class="col-5"> |
||||
<div class="h4"> </div> |
||||
{{ macros.change_log(context.model) }} |
||||
</div> |
||||
|
||||
{% endblock content %} |
||||
|
||||
|
Loading…
Reference in new issue