Allow changing status, adding notes for customer order items
This commit is contained in:
parent
7c6c2f7ded
commit
ab517d1199
317
tailbone/templates/custorders/items/view.mako
Normal file
317
tailbone/templates/custorders/items/view.mako
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
## -*- coding: utf-8; -*-
|
||||||
|
<%inherit file="/master/view.mako" />
|
||||||
|
|
||||||
|
<%def name="render_buefy_form()">
|
||||||
|
<div class="form">
|
||||||
|
<${form.component} ref="mainForm"
|
||||||
|
% if master.has_perm('change_status'):
|
||||||
|
@change-status="showChangeStatus"
|
||||||
|
% endif
|
||||||
|
% if master.has_perm('add_note'):
|
||||||
|
@add-note="showAddNote"
|
||||||
|
% endif
|
||||||
|
>
|
||||||
|
</${form.component}>
|
||||||
|
</div>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="page_content()">
|
||||||
|
${parent.page_content()}
|
||||||
|
|
||||||
|
% if master.has_perm('change_status'):
|
||||||
|
<b-modal :active.sync="showChangeStatusDialog">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="level">
|
||||||
|
<div class="level-left">
|
||||||
|
|
||||||
|
<div class="level-item">
|
||||||
|
Current status is:
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="level-item has-text-weight-bold">
|
||||||
|
{{ orderItemStatuses[oldStatusCode] }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="level-item"
|
||||||
|
style="margin-left: 5rem;">
|
||||||
|
New status will be:
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<b-field class="level-item"
|
||||||
|
:type="newStatusCode ? null : 'is-danger'">
|
||||||
|
<b-select v-model="newStatusCode">
|
||||||
|
<option v-for="item in orderItemStatusOptions"
|
||||||
|
:key="item.key"
|
||||||
|
:value="item.key">
|
||||||
|
{{ item.label }}
|
||||||
|
</option>
|
||||||
|
</b-select>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="changeStatusGridData.length">
|
||||||
|
|
||||||
|
<p class="block">
|
||||||
|
Please indicate any other item(s) to which the new
|
||||||
|
status should be applied:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<b-table :data="changeStatusGridData"
|
||||||
|
checkable
|
||||||
|
:checked-rows.sync="changeStatusCheckedRows"
|
||||||
|
narrowed
|
||||||
|
class="is-size-7">
|
||||||
|
<template slot-scope="props">
|
||||||
|
<b-table-column field="product_brand" label="Brand">
|
||||||
|
<span v-html="props.row.product_brand"></span>
|
||||||
|
</b-table-column>
|
||||||
|
<b-table-column field="product_description" label="Product">
|
||||||
|
<span v-html="props.row.product_description"></span>
|
||||||
|
</b-table-column>
|
||||||
|
<!-- <b-table-column field="quantity" label="Quantity"> -->
|
||||||
|
<!-- <span v-html="props.row.quantity"></span> -->
|
||||||
|
<!-- </b-table-column> -->
|
||||||
|
<b-table-column field="product_case_quantity" label="cPack">
|
||||||
|
<span v-html="props.row.product_case_quantity"></span>
|
||||||
|
</b-table-column>
|
||||||
|
<b-table-column field="order_quantity" label="oQty">
|
||||||
|
<span v-html="props.row.order_quantity"></span>
|
||||||
|
</b-table-column>
|
||||||
|
<b-table-column field="order_uom" label="UOM">
|
||||||
|
<span v-html="props.row.order_uom"></span>
|
||||||
|
</b-table-column>
|
||||||
|
<b-table-column field="department_name" label="Department">
|
||||||
|
<span v-html="props.row.department_name"></span>
|
||||||
|
</b-table-column>
|
||||||
|
<b-table-column field="product_barcode" label="Product Barcode">
|
||||||
|
<span v-html="props.row.product_barcode"></span>
|
||||||
|
</b-table-column>
|
||||||
|
<b-table-column field="unit_price" label="Unit $">
|
||||||
|
<span v-html="props.row.unit_price"></span>
|
||||||
|
</b-table-column>
|
||||||
|
<b-table-column field="total_price" label="Total $">
|
||||||
|
<span v-html="props.row.total_price"></span>
|
||||||
|
</b-table-column>
|
||||||
|
<b-table-column field="order_date" label="Order Date">
|
||||||
|
<span v-html="props.row.order_date"></span>
|
||||||
|
</b-table-column>
|
||||||
|
<b-table-column field="status_code" label="Status">
|
||||||
|
<span v-html="props.row.status_code"></span>
|
||||||
|
</b-table-column>
|
||||||
|
<!-- <b-table-column field="flagged" label="Flagged"> -->
|
||||||
|
<!-- <span v-html="props.row.flagged"></span> -->
|
||||||
|
<!-- </b-table-column> -->
|
||||||
|
</template>
|
||||||
|
</b-table>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Please provide a note<span v-if="changeStatusGridData.length">
|
||||||
|
(will be applied to all selected items)</span>:
|
||||||
|
</p>
|
||||||
|
<b-input v-model="newStatusNote"
|
||||||
|
type="textarea" rows="2">
|
||||||
|
</b-input>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<b-button type="is-primary"
|
||||||
|
:disabled="changeStatusSaveDisabled"
|
||||||
|
icon-pack="fas"
|
||||||
|
icon-left="save"
|
||||||
|
@click="statusChangeSave()">
|
||||||
|
{{ changeStatusSubmitText }}
|
||||||
|
</b-button>
|
||||||
|
<b-button @click="cancelStatusChange">
|
||||||
|
Cancel
|
||||||
|
</b-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</b-modal>
|
||||||
|
${h.form(master.get_action_url('change_status', instance), ref='changeStatusForm')}
|
||||||
|
${h.csrf_token(request)}
|
||||||
|
${h.hidden('new_status_code', **{'v-model': 'newStatusCode'})}
|
||||||
|
${h.hidden('uuids', **{':value': 'changeStatusCheckedRows.map((row) => {return row.uuid}).join()'})}
|
||||||
|
${h.hidden('note', **{':value': 'newStatusNote'})}
|
||||||
|
${h.end_form()}
|
||||||
|
% endif
|
||||||
|
|
||||||
|
% if master.has_perm('add_note'):
|
||||||
|
<b-modal has-modal-card
|
||||||
|
:active.sync="showAddNoteDialog">
|
||||||
|
<div class="modal-card">
|
||||||
|
|
||||||
|
<header class="modal-card-head">
|
||||||
|
<p class="modal-card-title">Add Note</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="modal-card-body">
|
||||||
|
<b-field>
|
||||||
|
<b-input type="textarea" rows="8"
|
||||||
|
v-model="newNoteText"
|
||||||
|
ref="newNoteTextArea">
|
||||||
|
</b-input>
|
||||||
|
</b-field>
|
||||||
|
<b-field>
|
||||||
|
<b-checkbox v-model="newNoteApplyAll">
|
||||||
|
Apply to all items on this order
|
||||||
|
</b-checkbox>
|
||||||
|
</b-field>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer class="modal-card-foot">
|
||||||
|
<b-button type="is-primary"
|
||||||
|
@click="addNoteSave()"
|
||||||
|
:disabled="addNoteSaveDisabled"
|
||||||
|
icon-pack="fas"
|
||||||
|
icon-left="save">
|
||||||
|
{{ addNoteSubmitText }}
|
||||||
|
</b-button>
|
||||||
|
<b-button @click="showAddNoteDialog = false">
|
||||||
|
Cancel
|
||||||
|
</b-button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</b-modal>
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="modify_this_page_vars()">
|
||||||
|
${parent.modify_this_page_vars()}
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
${form.component_studly}Data.notesData = ${json.dumps(notes_data)|n}
|
||||||
|
|
||||||
|
% if master.has_perm('change_status'):
|
||||||
|
|
||||||
|
ThisPageData.orderItemStatuses = ${json.dumps(enum.CUSTORDER_ITEM_STATUS)|n}
|
||||||
|
ThisPageData.orderItemStatusOptions = ${json.dumps([dict(key=k, label=v) for k, v in six.iteritems(enum.CUSTORDER_ITEM_STATUS)])|n}
|
||||||
|
|
||||||
|
ThisPageData.oldStatusCode = ${instance.status_code}
|
||||||
|
|
||||||
|
ThisPageData.showChangeStatusDialog = false
|
||||||
|
ThisPageData.newStatusCode = null
|
||||||
|
ThisPageData.changeStatusGridData = ${json.dumps(other_order_items_data)|n}
|
||||||
|
ThisPageData.changeStatusCheckedRows = []
|
||||||
|
ThisPageData.newStatusNote = null
|
||||||
|
ThisPageData.changeStatusSubmitText = "Update Status"
|
||||||
|
ThisPageData.changeStatusSubmitting = false
|
||||||
|
|
||||||
|
ThisPage.computed.changeStatusSaveDisabled = function() {
|
||||||
|
if (!this.newStatusCode) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (this.changeStatusSubmitting) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ThisPage.methods.showChangeStatus = function() {
|
||||||
|
this.newStatusCode = null
|
||||||
|
// clear out any checked rows
|
||||||
|
this.changeStatusCheckedRows.length = 0
|
||||||
|
this.newStatusNote = null
|
||||||
|
this.showChangeStatusDialog = true
|
||||||
|
}
|
||||||
|
|
||||||
|
ThisPage.methods.cancelStatusChange = function() {
|
||||||
|
this.showChangeStatusDialog = false
|
||||||
|
}
|
||||||
|
|
||||||
|
ThisPage.methods.statusChangeSave = function() {
|
||||||
|
if (this.newStatusCode == this.oldStatusCode) {
|
||||||
|
alert("You chose the same status it already had...")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.changeStatusSubmitting = true
|
||||||
|
this.changeStatusSubmitText = "Working, please wait..."
|
||||||
|
this.$refs.changeStatusForm.submit()
|
||||||
|
}
|
||||||
|
|
||||||
|
% endif
|
||||||
|
|
||||||
|
% if master.has_perm('add_note'):
|
||||||
|
|
||||||
|
ThisPageData.showAddNoteDialog = false
|
||||||
|
ThisPageData.newNoteText = null
|
||||||
|
ThisPageData.newNoteApplyAll = false
|
||||||
|
ThisPageData.addNoteSubmitting = false
|
||||||
|
ThisPageData.addNoteSubmitText = "Save Note"
|
||||||
|
|
||||||
|
ThisPage.computed.addNoteSaveDisabled = function() {
|
||||||
|
if (!this.newNoteText) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (this.addNoteSubmitting) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ThisPage.methods.showAddNote = function() {
|
||||||
|
this.newNoteText = null
|
||||||
|
this.newNoteApplyAll = false
|
||||||
|
this.showAddNoteDialog = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.newNoteTextArea.focus()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ThisPage.methods.addNoteSave = function() {
|
||||||
|
this.addNoteSubmitting = true
|
||||||
|
this.addNoteSubmitText = "Working, please wait..."
|
||||||
|
|
||||||
|
let url = '${url('{}.add_note'.format(route_prefix), uuid=instance.uuid)}'
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
note: this.newNoteText,
|
||||||
|
apply_all: this.newNoteApplyAll,
|
||||||
|
}
|
||||||
|
|
||||||
|
let headers = {
|
||||||
|
## TODO: should find a better way to handle CSRF token
|
||||||
|
'X-CSRF-TOKEN': this.csrftoken,
|
||||||
|
}
|
||||||
|
|
||||||
|
## TODO: should find a better way to handle CSRF token
|
||||||
|
this.$http.post(url, params, {headers: headers}).then(({ data }) => {
|
||||||
|
if (data.success) {
|
||||||
|
this.$refs.mainForm.notesData = data.notes
|
||||||
|
this.showAddNoteDialog = false
|
||||||
|
} else {
|
||||||
|
this.$buefy.toast.open({
|
||||||
|
message: "Save failed: " + (data.error || "(unknown error)"),
|
||||||
|
type: 'is-danger',
|
||||||
|
duration: 4000, // 4 seconds
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.addNoteSubmitting = false
|
||||||
|
this.addNoteSubmitText = "Save Note"
|
||||||
|
}).catch((error) => {
|
||||||
|
// TODO: should handle this better somehow..?
|
||||||
|
this.$buefy.toast.open({
|
||||||
|
message: "Save failed: (unknown error)",
|
||||||
|
type: 'is-danger',
|
||||||
|
duration: 4000, // 4 seconds
|
||||||
|
})
|
||||||
|
this.addNoteSubmitting = false
|
||||||
|
this.addNoteSubmitText = "Save Note"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
% endif
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
${parent.body()}
|
|
@ -34,7 +34,7 @@ from sqlalchemy import orm
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
from rattail.time import localtime
|
from rattail.time import localtime
|
||||||
|
|
||||||
from webhelpers2.html import tags
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
from tailbone.views import MasterView
|
from tailbone.views import MasterView
|
||||||
from tailbone.util import raw_datetime
|
from tailbone.util import raw_datetime
|
||||||
|
@ -54,6 +54,7 @@ class CustomerOrderItemView(MasterView):
|
||||||
labels = {
|
labels = {
|
||||||
'order_id': "Order ID",
|
'order_id': "Order ID",
|
||||||
'order_uom': "Order UOM",
|
'order_uom': "Order UOM",
|
||||||
|
'status_code': "Status",
|
||||||
}
|
}
|
||||||
|
|
||||||
grid_columns = [
|
grid_columns = [
|
||||||
|
@ -99,6 +100,7 @@ class CustomerOrderItemView(MasterView):
|
||||||
'total_price',
|
'total_price',
|
||||||
'paid_amount',
|
'paid_amount',
|
||||||
'status_code',
|
'status_code',
|
||||||
|
'notes',
|
||||||
]
|
]
|
||||||
|
|
||||||
def query(self, session):
|
def query(self, session):
|
||||||
|
@ -139,7 +141,6 @@ class CustomerOrderItemView(MasterView):
|
||||||
g.set_label('product_brand', "Brand")
|
g.set_label('product_brand', "Brand")
|
||||||
g.set_label('product_description', "Description")
|
g.set_label('product_description', "Description")
|
||||||
g.set_label('product_size', "Size")
|
g.set_label('product_size', "Size")
|
||||||
g.set_label('status_code', "Status")
|
|
||||||
|
|
||||||
g.set_link('order_id')
|
g.set_link('order_id')
|
||||||
g.set_link('person')
|
g.set_link('person')
|
||||||
|
@ -161,6 +162,7 @@ class CustomerOrderItemView(MasterView):
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(CustomerOrderItemView, self).configure_form(f)
|
super(CustomerOrderItemView, self).configure_form(f)
|
||||||
|
use_buefy = self.get_use_buefy()
|
||||||
|
|
||||||
# order
|
# order
|
||||||
f.set_renderer('order', self.render_order)
|
f.set_renderer('order', self.render_order)
|
||||||
|
@ -187,10 +189,193 @@ class CustomerOrderItemView(MasterView):
|
||||||
# person
|
# person
|
||||||
f.set_renderer('person', self.render_person)
|
f.set_renderer('person', self.render_person)
|
||||||
|
|
||||||
f.set_enum('status_code', self.enum.CUSTORDER_ITEM_STATUS)
|
# status_code
|
||||||
|
f.set_renderer('status_code', self.render_status_code)
|
||||||
|
|
||||||
# label overrides
|
# notes
|
||||||
f.set_label('status_code', "Status")
|
if use_buefy:
|
||||||
|
f.set_renderer('notes', self.render_notes)
|
||||||
|
else:
|
||||||
|
f.remove('notes')
|
||||||
|
|
||||||
|
def render_status_code(self, item, field):
|
||||||
|
use_buefy = self.get_use_buefy()
|
||||||
|
text = self.enum.CUSTORDER_ITEM_STATUS[item.status_code]
|
||||||
|
items = [HTML.tag('span', c=[text])]
|
||||||
|
|
||||||
|
if use_buefy and self.has_perm('change_status'):
|
||||||
|
button = HTML.tag('b-button', type='is-primary', c="Change Status",
|
||||||
|
style='margin-left: 1rem;',
|
||||||
|
icon_pack='fas', icon_left='edit',
|
||||||
|
**{'@click': "$emit('change-status')"})
|
||||||
|
items.append(button)
|
||||||
|
|
||||||
|
left = HTML.tag('div', class_='level-left', c=items)
|
||||||
|
outer = HTML.tag('div', class_='level', c=[left])
|
||||||
|
return outer
|
||||||
|
|
||||||
|
def render_notes(self, item, field):
|
||||||
|
route_prefix = self.get_route_prefix()
|
||||||
|
|
||||||
|
factory = self.get_grid_factory()
|
||||||
|
g = factory(
|
||||||
|
key='{}.notes'.format(route_prefix),
|
||||||
|
data=[],
|
||||||
|
columns=[
|
||||||
|
'text',
|
||||||
|
'created_by',
|
||||||
|
'created',
|
||||||
|
],
|
||||||
|
labels={
|
||||||
|
'text': "Note",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
table = HTML.literal(
|
||||||
|
g.render_buefy_table_element(data_prop='notesData'))
|
||||||
|
elements = [table]
|
||||||
|
|
||||||
|
if self.has_perm('add_note'):
|
||||||
|
button = HTML.tag('b-button', type='is-primary', c="Add Note",
|
||||||
|
class_='is-pulled-right',
|
||||||
|
icon_pack='fas', icon_left='plus',
|
||||||
|
**{'@click': "$emit('add-note')"})
|
||||||
|
button_wrapper = HTML.tag('div', c=[button],
|
||||||
|
style='margin-top: 0.5rem;')
|
||||||
|
elements.append(button_wrapper)
|
||||||
|
|
||||||
|
return HTML.tag('div',
|
||||||
|
style='display: flex; flex-direction: column;',
|
||||||
|
c=elements)
|
||||||
|
|
||||||
|
def template_kwargs_view(self, **kwargs):
|
||||||
|
kwargs = super(CustomerOrderItemView, self).template_kwargs_view(**kwargs)
|
||||||
|
app = self.get_rattail_app()
|
||||||
|
item = kwargs['instance']
|
||||||
|
|
||||||
|
# fetch notes for current item
|
||||||
|
kwargs['notes_data'] = self.get_context_notes(item)
|
||||||
|
|
||||||
|
# fetch "other" order items, siblings of current one
|
||||||
|
order = item.order
|
||||||
|
other_items = self.Session.query(model.CustomerOrderItem)\
|
||||||
|
.filter(model.CustomerOrderItem.order == order)\
|
||||||
|
.filter(model.CustomerOrderItem.uuid != item.uuid)\
|
||||||
|
.all()
|
||||||
|
other_data = []
|
||||||
|
for other in other_items:
|
||||||
|
|
||||||
|
order_date = None
|
||||||
|
if order.created:
|
||||||
|
order_date = localtime(self.rattail_config, order.created, from_utc=True).date()
|
||||||
|
|
||||||
|
other_data.append({
|
||||||
|
'uuid': other.uuid,
|
||||||
|
'brand_name': other.product_brand,
|
||||||
|
'product_description': other.product_description,
|
||||||
|
'product_case_quantity': app.render_quantity(other.case_quantity),
|
||||||
|
'order_quantity': app.render_quantity(other.order_quantity),
|
||||||
|
'order_uom': self.enum.UNIT_OF_MEASURE[other.order_uom],
|
||||||
|
'department_name': other.department_name,
|
||||||
|
'product_barcode': other.product_upc.pretty() if other.product_upc else None,
|
||||||
|
'unit_price': app.render_currency(other.unit_price),
|
||||||
|
'total_price': app.render_currency(other.total_price),
|
||||||
|
'order_date': app.render_date(order_date),
|
||||||
|
'status_code': self.enum.CUSTORDER_ITEM_STATUS[other.status_code],
|
||||||
|
})
|
||||||
|
kwargs['other_order_items_data'] = other_data
|
||||||
|
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def get_context_notes(self, item):
|
||||||
|
notes = []
|
||||||
|
for note in reversed(item.notes):
|
||||||
|
created = localtime(self.rattail_config, note.created, from_utc=True)
|
||||||
|
notes.append({
|
||||||
|
'created': raw_datetime(self.rattail_config, created),
|
||||||
|
'created_by': note.created_by.display_name,
|
||||||
|
'text': note.text,
|
||||||
|
})
|
||||||
|
return notes
|
||||||
|
|
||||||
|
def change_status(self):
|
||||||
|
"""
|
||||||
|
View for changing status of one or more order items.
|
||||||
|
"""
|
||||||
|
order_item = self.get_instance()
|
||||||
|
redirect = self.redirect(self.get_action_url('view', order_item))
|
||||||
|
|
||||||
|
# validate new status
|
||||||
|
new_status_code = int(self.request.POST['new_status_code'])
|
||||||
|
if new_status_code not in self.enum.CUSTORDER_ITEM_STATUS:
|
||||||
|
self.request.session.flash("Invalid status code", 'error')
|
||||||
|
return redirect
|
||||||
|
|
||||||
|
# locate order items to which new status will be applied
|
||||||
|
order_items = [order_item]
|
||||||
|
uuids = self.request.POST['uuids']
|
||||||
|
if uuids:
|
||||||
|
for uuid in uuids.split(','):
|
||||||
|
item = self.Session.query(model.CustomerOrderItem).get(uuid)
|
||||||
|
if item:
|
||||||
|
order_items.append(item)
|
||||||
|
|
||||||
|
# locate user responsible for change
|
||||||
|
user = self.request.user
|
||||||
|
|
||||||
|
# maybe grab extra user-provided note to attach
|
||||||
|
extra_note = self.request.POST.get('note')
|
||||||
|
|
||||||
|
# apply new status to order item(s)
|
||||||
|
for item in order_items:
|
||||||
|
if item.status_code != new_status_code:
|
||||||
|
|
||||||
|
# attach event
|
||||||
|
note = "status changed from \"{}\" to \"{}\"".format(
|
||||||
|
self.enum.CUSTORDER_ITEM_STATUS[item.status_code],
|
||||||
|
self.enum.CUSTORDER_ITEM_STATUS[new_status_code])
|
||||||
|
if extra_note:
|
||||||
|
note = "{} - NOTE: {}".format(note, extra_note)
|
||||||
|
item.events.append(model.CustomerOrderItemEvent(
|
||||||
|
type_code=self.enum.CUSTORDER_ITEM_EVENT_STATUS_CHANGE,
|
||||||
|
user=user, note=note))
|
||||||
|
|
||||||
|
# change status
|
||||||
|
item.status_code = new_status_code
|
||||||
|
|
||||||
|
self.request.session.flash("Status has been updated to: {}".format(
|
||||||
|
self.enum.CUSTORDER_ITEM_STATUS[new_status_code]))
|
||||||
|
return redirect
|
||||||
|
|
||||||
|
def add_note(self):
|
||||||
|
"""
|
||||||
|
View for adding a new note to current order item, optinally
|
||||||
|
also adding it to all other items under the parent order.
|
||||||
|
"""
|
||||||
|
order_item = self.get_instance()
|
||||||
|
data = self.request.json_body
|
||||||
|
new_note = data['note']
|
||||||
|
apply_all = data['apply_all'] == True
|
||||||
|
user = self.request.user
|
||||||
|
|
||||||
|
if apply_all:
|
||||||
|
order_items = order_item.order.items
|
||||||
|
else:
|
||||||
|
order_items = [order_item]
|
||||||
|
|
||||||
|
for item in order_items:
|
||||||
|
item.notes.append(model.CustomerOrderItemNote(
|
||||||
|
created_by=user, text=new_note))
|
||||||
|
|
||||||
|
# # attach event
|
||||||
|
# item.events.append(model.CustomerOrderItemEvent(
|
||||||
|
# type_code=self.enum.CUSTORDER_ITEM_EVENT_ADDED_NOTE,
|
||||||
|
# user=user, note=new_note))
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
self.Session.refresh(order_item)
|
||||||
|
return {'success': True,
|
||||||
|
'notes': self.get_context_notes(order_item)}
|
||||||
|
|
||||||
def render_order(self, item, field):
|
def render_order(self, item, field):
|
||||||
order = item.order
|
order = item.order
|
||||||
|
@ -210,16 +395,58 @@ class CustomerOrderItemView(MasterView):
|
||||||
def get_row_data(self, item):
|
def get_row_data(self, item):
|
||||||
return self.Session.query(model.CustomerOrderItemEvent)\
|
return self.Session.query(model.CustomerOrderItemEvent)\
|
||||||
.filter(model.CustomerOrderItemEvent.item == item)\
|
.filter(model.CustomerOrderItemEvent.item == item)\
|
||||||
.order_by(model.CustomerOrderItemEvent.occurred,
|
.order_by(model.CustomerOrderItemEvent.occurred.desc(),
|
||||||
model.CustomerOrderItemEvent.type_code)
|
model.CustomerOrderItemEvent.type_code)
|
||||||
|
|
||||||
def configure_row_grid(self, g):
|
def configure_row_grid(self, g):
|
||||||
super(CustomerOrderItemView, self).configure_row_grid(g)
|
super(CustomerOrderItemView, self).configure_row_grid(g)
|
||||||
|
|
||||||
|
g.set_enum('type_code', self.enum.CUSTORDER_ITEM_EVENT)
|
||||||
|
|
||||||
g.set_label('occurred', "When")
|
g.set_label('occurred', "When")
|
||||||
g.set_label('type_code', "What") # TODO: enum renderer
|
g.set_label('type_code', "What") # TODO: enum renderer
|
||||||
g.set_label('user', "Who")
|
g.set_label('user', "Who")
|
||||||
g.set_label('note', "Notes")
|
g.set_label('note', "Notes")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def defaults(cls, config):
|
||||||
|
cls._order_item_defaults(config)
|
||||||
|
cls._defaults(config)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _order_item_defaults(cls, config):
|
||||||
|
route_prefix = cls.get_route_prefix()
|
||||||
|
instance_url_prefix = cls.get_instance_url_prefix()
|
||||||
|
permission_prefix = cls.get_permission_prefix()
|
||||||
|
model_title_plural = cls.get_model_title_plural()
|
||||||
|
|
||||||
|
# fix permission group name
|
||||||
|
config.add_tailbone_permission_group(permission_prefix, model_title_plural)
|
||||||
|
|
||||||
|
# change status
|
||||||
|
config.add_tailbone_permission(permission_prefix,
|
||||||
|
'{}.change_status'.format(permission_prefix),
|
||||||
|
"Change status for 1 or more {}".format(model_title_plural))
|
||||||
|
config.add_route('{}.change_status'.format(route_prefix),
|
||||||
|
'{}/change-status'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='change_status',
|
||||||
|
route_name='{}.change_status'.format(route_prefix),
|
||||||
|
permission='{}.change_status'.format(permission_prefix))
|
||||||
|
|
||||||
|
# add note
|
||||||
|
config.add_tailbone_permission(permission_prefix,
|
||||||
|
'{}.add_note'.format(permission_prefix),
|
||||||
|
"Add arbitrary notes for {}".format(model_title_plural))
|
||||||
|
config.add_route('{}.add_note'.format(route_prefix),
|
||||||
|
'{}/add-note'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='add_note',
|
||||||
|
route_name='{}.add_note'.format(route_prefix),
|
||||||
|
renderer='json',
|
||||||
|
permission='{}.add_note'.format(permission_prefix))
|
||||||
|
|
||||||
|
|
||||||
# TODO: deprecate / remove this
|
# TODO: deprecate / remove this
|
||||||
CustomerOrderItemsView = CustomerOrderItemView
|
CustomerOrderItemsView = CustomerOrderItemView
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,11 @@ class CustomerOrderView(MasterView):
|
||||||
route_prefix = 'custorders'
|
route_prefix = 'custorders'
|
||||||
editable = False
|
editable = False
|
||||||
|
|
||||||
|
labels = {
|
||||||
|
'id': "ID",
|
||||||
|
'status_code': "Status",
|
||||||
|
}
|
||||||
|
|
||||||
grid_columns = [
|
grid_columns = [
|
||||||
'id',
|
'id',
|
||||||
'customer',
|
'customer',
|
||||||
|
@ -117,10 +122,6 @@ class CustomerOrderView(MasterView):
|
||||||
|
|
||||||
g.set_sort_defaults('created', 'desc')
|
g.set_sort_defaults('created', 'desc')
|
||||||
|
|
||||||
# TODO: enum choices renderer
|
|
||||||
g.set_label('status_code', "Status")
|
|
||||||
g.set_label('id', "ID")
|
|
||||||
|
|
||||||
g.set_link('id')
|
g.set_link('id')
|
||||||
g.set_link('customer')
|
g.set_link('customer')
|
||||||
g.set_link('person')
|
g.set_link('person')
|
||||||
|
@ -129,7 +130,6 @@ class CustomerOrderView(MasterView):
|
||||||
super(CustomerOrderView, self).configure_form(f)
|
super(CustomerOrderView, self).configure_form(f)
|
||||||
|
|
||||||
f.set_readonly('id')
|
f.set_readonly('id')
|
||||||
f.set_label('id', "ID")
|
|
||||||
|
|
||||||
f.set_renderer('store', self.render_store)
|
f.set_renderer('store', self.render_store)
|
||||||
f.set_renderer('customer', self.render_customer)
|
f.set_renderer('customer', self.render_customer)
|
||||||
|
@ -138,7 +138,6 @@ class CustomerOrderView(MasterView):
|
||||||
f.set_type('total_price', 'currency')
|
f.set_type('total_price', 'currency')
|
||||||
|
|
||||||
f.set_enum('status_code', self.enum.CUSTORDER_STATUS)
|
f.set_enum('status_code', self.enum.CUSTORDER_STATUS)
|
||||||
f.set_label('status_code', "Status")
|
|
||||||
|
|
||||||
f.set_readonly('created')
|
f.set_readonly('created')
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue