Browse Source

added editing orders and placing custom orders

splash screen for new orders still missing
php2python
Holger Frey 7 years ago
parent
commit
b9e3be30ce
  1. 26
      ordr2/models/orders.py
  2. 39
      ordr2/schemas/orders.py
  3. 10
      ordr2/static/css/style.css
  4. 28
      ordr2/static/js/functions.js
  5. 71
      ordr2/templates/deform/order_info_mapping.pt
  6. 24
      ordr2/templates/orders/edit.jinja2
  7. 2
      ordr2/templates/orders/list.jinja2
  8. 24
      ordr2/templates/orders/new.jinja2
  9. 173
      ordr2/views/orders.py

26
ordr2/models/orders.py

@ -96,3 +96,29 @@ class Order(Base): @@ -96,3 +96,29 @@ class Order(Base):
def __str__(self):
''' string representation '''
return '{!s} ({!s})'.format(self.cas_description, self.vendor)
def _date_info(self, some_date, some_one):
if not some_date:
return ''
if some_one:
return '{!s} by {!s}'.format(some_date, some_one)
else:
return '{!s}'.format(some_date)
@property
def placed(self):
return self._date_info(self.created_date, self.created_by)
@property
def approved(self):
return self._date_info(self.approval_date, self.approval_by)
@property
def ordered(self):
return self._date_info(self.ordered_date, self.ordered_by)
@property
def completed(self):
return self._date_info(self.completed_date, self.completed_by)

39
ordr2/schemas/orders.py

@ -66,33 +66,12 @@ class ConsumableSchema(CSRFSchema): @@ -66,33 +66,12 @@ class ConsumableSchema(CSRFSchema):
return super().as_form(request, **settings)
class OrderInformation(colander.Schema):
status = colander.SchemaNode(
colander.String(),
widget=deform.widget.SelectWidget(values=STATI)
)
placed = colander.SchemaNode(
colander.String(),
widget=deform.widget.TextInputWidget(readonly=True),
missing=''
)
approval = colander.SchemaNode(
colander.String(),
widget=deform.widget.TextInputWidget(readonly=True),
missing=''
)
ordered = colander.SchemaNode(
colander.String(),
widget=deform.widget.TextInputWidget(readonly=True),
missing=''
)
completed = colander.SchemaNode(
colander.String(),
widget=deform.widget.TextInputWidget(readonly=True),
missing=''
)
class OrderItem(colander.Schema):
@ -123,6 +102,9 @@ class OrderPricing(colander.Schema): @@ -123,6 +102,9 @@ class OrderPricing(colander.Schema):
quantity = colander.SchemaNode(
colander.Integer(),
validator=colander.Range(min=1),
widget=deform.widget.TextInputWidget(
css_class='number'
),
default=1
)
total_price = MoneyInputSchema(
@ -148,12 +130,15 @@ class NewOrderSchema(CSRFSchema): @@ -148,12 +130,15 @@ class NewOrderSchema(CSRFSchema):
item_information = OrderItem()
pricing = OrderPricing()
optional_informatoin = OrderOptionals()
optional_information = OrderOptionals()
@classmethod
def as_form(cls, request, **override):
settings = {
'buttons': ('Place Order', 'Cancel'),
'buttons': (
deform.Button(name='save', title='Place Order'),
deform.Button(name='cancel', title='Cancel')
),
'css_class': 'form-horizontal'
}
settings.update(override)
@ -163,10 +148,14 @@ class NewOrderSchema(CSRFSchema): @@ -163,10 +148,14 @@ class NewOrderSchema(CSRFSchema):
class EditOrderSchema(CSRFSchema):
''' edit or add an order '''
order_information = OrderInformation()
order_information = OrderInformation(
widget=deform.widget.MappingWidget(
template='order_info_mapping.pt'
)
)
item_information = OrderItem()
pricing = OrderPricing()
optional_informatoin = OrderOptionals()
optional_information = OrderOptionals()
@classmethod
def as_form(cls, request, **override):

10
ordr2/static/css/style.css

@ -725,15 +725,17 @@ input[value="password:mapping"] + div { margin-bottom:10px; } @@ -725,15 +725,17 @@ input[value="password:mapping"] + div { margin-bottom:10px; }
input[value="new_password:mapping"] + div { margin-bottom:10px; }
.form-horizontal.user-settings fieldset > .controls { margin-left:0; }
.user-settings .panel-heading {
.user-settings .panel-heading,
.edit-order .panel-heading {
font-size:150%;
padding-top: 20px;
padding-bottom: 20px;
margin-bottom: 20px;
border-bottom: 1px solid #aaa;}
div.alert a { color:inherit; text-decoration:underline; }
td.column-pkg, td.column-price { text-align:right; }
td.column-pkg, td.column-price, td.column-total, td.column-amount {
text-align:right;}
input.number { text-align:right; }
.moneyinput .amount { width:167px; text-align:right;}
.moneyinput .currency { width:30px; text-align:center;}
.controls .form-control-static { padding-top:5px; }

28
ordr2/static/js/functions.js

@ -89,29 +89,29 @@ $(document).ready(function() { @@ -89,29 +89,29 @@ $(document).ready(function() {
});
// calculator
if ( $('input[name="price_unit"]').length ) {
if( $('input[name="price_unit"]').val() != '' && $('input[name="quantity"]').val() != '' ){
var total = $('input[name="price_unit"]').val().replace(",", ".") * $('input[name="quantity"]').val();
if ( $('.item-unit_price input[name="amount"]').length ) {
if( $('.item-unit_price input[name="amount"]').val() != '' && $('input[name="quantity"]').val() != '' ){
var total = $('.item-unit_price input[name="amount"]').val().replace(",", "") * $('input[name="quantity"]').val();
total = Math.round(total*100)/100;
$('input[name="price_total_disabled"]').attr( 'placeholder', total );
$('.item-total_price input[name="amount"]').attr( 'value', total );
}
$('input[name="price_unit"], input[name="quantity"]').keyup(function() {
var total = $('input[name="price_unit"]').val().replace(",", ".") * $('input[name="quantity"]').val();
$('.item-unit_price input[name="amount"], input[name="quantity"]').keyup(function() {
var total = $('.item-unit_price input[name="amount"]').val().replace(",", "") * $('input[name="quantity"]').val();
total = Math.round(total*100)/100;
$('input[name="price_total_disabled"]').attr( 'placeholder', total );
$('.item-total_price input[name="amount"]').attr( 'value', total );
});
}
if ( $('input[name="currency"]').length ) {
if ( $('.item-unit_price input[name="currency"]').length ) {
// added currency to total price
if( $('input[name="currency"]').val() != '' ){
$('input[name="currency_disabled"]').attr( 'placeholder', $('input[name="currency"]').val() );
if( $('.item-unit_price input[name="currency"]').val() != '' ){
$('.item-total_price input[name="currency"]').attr( 'value', $('.item-unit_price input[name="currency"]').val() );
}
$('input[name="currency"]').keyup(function() {
$('input[name="currency_disabled"]').attr( 'placeholder', $('input[name="currency"]').val() );
$('.item-unit_price input[name="currency"]').keyup(function() {
$('.item-total_price input[name="currency"]').attr( 'value', $('.item-unit_price input[name="currency"]').val() );
});
$('input[name="currency"]').change(function() {
$('input[name="currency_disabled"]').attr( 'placeholder', $('input[name="currency"]').val() );
$('.item-unit_price input[name="currency"]').change(function() {
$('.item-total_price input[name="currency"]').attr( 'value', $('.item-unit_price input[name="currency"]').val() );
});
}

71
ordr2/templates/deform/order_info_mapping.pt

@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
<tal:def tal:define="title title|field.title;
description description|field.description;
errormsg errormsg|field.errormsg;
item_template item_template|field.widget.item_template;
request field.schema.bindings['request']"
i18n:domain="deform">
<div class="panel panel-default" title="${description}">
<div class="panel-heading">${title}</div>
<div class="panel-body">
<div tal:condition="errormsg"
class="clearfix alert alert-danger">
<p i18n:translate="">
There was a problem with this section
</p>
<p>${errormsg}</p>
</div>
<div tal:condition="description">
${description}
</div>
${field.start_mapping()}
<div tal:repeat="child field.children"
tal:replace="structure child.render_template(item_template)" >
</div>
<div class="control-group">
<label class="control-label"> Placed </label>
<div class="controls">
<p class="form-control-static">
${request.context.model.placed}
</p>
</div>
</div>
<div class="control-group">
<label class="control-label"> Approved </label>
<div class="controls">
<p class="form-control-static">
${request.context.model.approved}
</p>
</div>
</div>
<div class="control-group">
<label class="control-label"> Ordered </label>
<div class="controls">
<p class="form-control-static">
${request.context.model.ordered}
</p>
</div>
</div>
<div class="control-group">
<label class="control-label"> Completed </label>
<div class="controls">
<p class="form-control-static">
${request.context.model.completed}
</p>
</div>
</div>
${field.end_mapping()}
</div>
</div>
</tal:def>

24
ordr2/templates/orders/edit.jinja2

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
{% extends "ordr2:templates/layout.jinja2" %}
{% import 'ordr2:templates/macros.jinja2' as macros with context %}
{% block subtitle %} Order | {{ context.model.cas_description }} {% endblock subtitle %}
{% block content %}
<div class="content controls">
<div class="container-fluid">
<div class="row-fluid">
<div class="page-controls">
<h1>Edit Order: {{ context.model.cas_description }}</h1>
</div>
</div>
<div class="row edit-order">
<div class="span8">
{{ macros.flash_messages() }}
{{form.render()|safe}}
</div>
</div>
</div>
</div>
{% endblock content %}

2
ordr2/templates/orders/order_list.jinja2 → ordr2/templates/orders/list.jinja2

@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
</div>
<div class="span10">
<form action="{{ request.resource_url(context, 'actions') }}" method="POST">
<form action="{{ request.resource_url(context, 'actions', query=context.query_params()) }}" method="POST">
<input type="hidden" name="csrf_token" value="{{get_csrf_token()}}">
<div class="page-controls">
<div class="input-append search">

24
ordr2/templates/orders/new.jinja2

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
{% extends "ordr2:templates/layout.jinja2" %}
{% import 'ordr2:templates/macros.jinja2' as macros with context %}
{% block subtitle %} Order | Create New Order {% endblock subtitle %}
{% block content %}
<div class="content controls">
<div class="container-fluid">
<div class="row-fluid">
<div class="page-controls">
<h1>Create New Order</h1>
</div>
</div>
<div class="row edit-order">
<div class="span8">
{{ macros.flash_messages() }}
{{form.render()|safe}}
</div>
</div>
</div>
</div>
{% endblock content %}

173
ordr2/views/orders.py

@ -1,12 +1,14 @@ @@ -1,12 +1,14 @@
import deform
from datetime import datetime
from pyramid.httpexceptions import HTTPFound
from pyramid.renderers import render
from pyramid.view import view_config
from ordr2.events import OrderStatusChange
from ordr2.models import Category, Order, OrderStatus, User
from ordr2.schemas.orders import ConsumableSchema
from ordr2.schemas.orders import NewOrderSchema, EditOrderSchema
from . import update_column_display
@ -34,7 +36,7 @@ def change_in_order_status(request, order, old): @@ -34,7 +36,7 @@ def change_in_order_status(request, order, old):
@view_config(
context='ordr2:resources.OrderList',
permission='view',
renderer='ordr2:templates/orders/order_list.jinja2'
renderer='ordr2:templates/orders/list.jinja2'
)
def order_list(context, request):
''' display the order list '''
@ -174,11 +176,178 @@ def order_delete_form(context, request): @@ -174,11 +176,178 @@ def order_delete_form(context, request):
return {'orders': [context.model]}
@view_config(
context='ordr2:resources.OrderResource',
name='edit',
permission='edit',
request_method='GET',
renderer='ordr2:templates/orders/edit.jinja2'
)
def order_edit_form(context, request):
form = EditOrderSchema.as_form(request)
order = context.model
info = {
'status': order.status.name
}
item = {
'cas_description': order.cas_description,
'category': order.category.name,
'vendor': order.vendor,
'catalog_nr': order.catalog_nr,
'package_size': order.package_size
}
pricing = {
'unit_price': {
'amount': '%.2f' % order.unit_price,
'currency': order.currency
},
'quantity': order.amount,
'total_price': {
'amount': '%.2f' % order.total_price,
'currency': order.currency
},
}
optional = {
'account': order.account,
'comment': order.comment
}
form_data = {
'order_information': info,
'item_information': item,
'pricing': pricing,
'optional_information': optional
}
form.set_appstruct(form_data)
return {'form': form}
@view_config(
context='ordr2:resources.OrderResource',
name='edit',
permission='edit',
request_method='POST',
renderer='ordr2:templates/orders/edit.jinja2'
)
def order_edit_form_processing(context, request):
''' process the consumable edit form '''
form = EditOrderSchema.as_form(request)
data = request.POST.items()
if 'save' in request.POST:
try:
appstruct = form.validate(data)
except deform.ValidationFailure as e:
return {'form': form}
# form validation sucessful, change order
order = context.model
info = appstruct['order_information']
item = appstruct['item_information']
pricing = appstruct['pricing']
optional = appstruct['optional_information']
old_status = order.status
order.status = OrderStatus[info['status']]
order.cas_description = item['cas_description']
order.category = item['category']
order.vendor = item['vendor']
order.catalog_nr = item['catalog_nr']
order.package_size = item['package_size']
order.unit_price = pricing['unit_price']['amount']
order.currency = pricing['unit_price']['currency']
order.amount = pricing['quantity']
order.total_price = order.unit_price * order.amount
order.account = optional['account']
order.comment = optional['comment']
if old_status != order.status:
change_in_order_status(request, order, old_status)
if order.status == OrderStatus.APPROVAL:
order.approval_date = datetime.utcnow()
order.approval_by = request.user.user_name
if order.status == OrderStatus.ORDERED:
order.ordered_date = datetime.utcnow()
order.ordered_by = request.user.user_name
if order.status == OrderStatus.COMPLETED:
order.completed_date = datetime.utcnow()
order.completed_by = request.user.user_name
msg = 'Order <em>{!s}</em> updated.'.format(context.model)
request.flash('success', msg)
elif 'delete' in request.POST and context.model:
return HTTPFound(request.resource_url(context, 'delete'))
return HTTPFound(context.__parent__.url())
@view_config(
context='ordr2:resources.OrderList',
name='new',
permission='create',
request_method='GET',
renderer='ordr2:templates/orders/new.jinja2'
)
def order_new_form(context, request):
form = NewOrderSchema.as_form(request)
return {'form': form}
@view_config(
context='ordr2:resources.OrderList',
name='new',
permission='create',
request_method='POST',
renderer='ordr2:templates/orders/new.jinja2'
)
def order_new_form_processing(context, request):
''' process the consumable edit form '''
form = NewOrderSchema.as_form(request)
data = request.POST.items()
if 'save' in request.POST:
try:
appstruct = form.validate(data)
except deform.ValidationFailure as e:
return {'form': form}
# form validation sucessful, change order
order = Order(
status=OrderStatus.OPEN,
created_by=request.user.user_name
)
item = appstruct['item_information']
pricing = appstruct['pricing']
optional = appstruct['optional_information']
order.cas_description = item['cas_description']
order.category = item['category']
order.vendor = item['vendor']
order.catalog_nr = item['catalog_nr']
order.package_size = item['package_size']
order.unit_price = pricing['unit_price']['amount']
order.currency = pricing['unit_price']['currency']
order.amount = pricing['quantity']
order.total_price = order.unit_price * order.amount
order.account = optional['account']
order.comment = optional['comment']
request.dbsession.add(order)
msg = 'Order <em>{!s}</em> created.'.format(context.model)
request.flash('success', msg)
return HTTPFound(context.url())