Add basic/unfinished "new customer order" page/feature

so far creates the order batch, and can set some customer info
This commit is contained in:
Lance Edgar 2020-08-02 20:59:16 -05:00
parent c32f47ba95
commit 808e737202
4 changed files with 639 additions and 2 deletions

View file

@ -26,8 +26,13 @@ Base class for customer order batch views
from __future__ import unicode_literals, absolute_import
import six
from rattail.db import model
import colander
from tailbone import forms
from tailbone.views.batch import BatchMasterView
@ -39,3 +44,79 @@ class CustomerOrderBatchView(BatchMasterView):
model_class = model.CustomerOrderBatch
model_row_class = model.CustomerOrderBatchRow
default_handler_spec = 'rattail.batch.custorder:CustomerOrderBatchHandler'
grid_columns = [
'id',
'customer',
'rows',
'created',
'created_by',
]
form_fields = [
'id',
'customer',
'person',
'phone_number',
'email_address',
'created',
'created_by',
'rows',
'status_code',
]
def configure_grid(self, g):
super(CustomerOrderBatchView, self).configure_grid(g)
g.set_link('customer')
g.set_link('created')
g.set_link('created_by')
def configure_form(self, f):
super(CustomerOrderBatchView, self).configure_form(f)
order = f.model_instance
model = self.rattail_config.get_model()
# readonly fields
f.set_readonly('rows')
f.set_readonly('status_code')
# customer
if 'customer' in f.fields and self.editing:
f.replace('customer', 'customer_uuid')
f.set_node('customer_uuid', colander.String(), missing=colander.null)
customer_display = ""
if self.request.method == 'POST':
if self.request.POST.get('customer_uuid'):
customer = self.Session.query(model.Customer)\
.get(self.request.POST['customer_uuid'])
if customer:
customer_display = six.text_type(customer)
elif self.editing:
customer_display = six.text_type(order.customer or "")
customers_url = self.request.route_url('customers.autocomplete')
f.set_widget('customer_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=customer_display, service_url=customers_url))
f.set_label('customer_uuid', "Customer")
else:
f.set_renderer('customer', self.render_customer)
# person
if 'person' in f.fields and self.editing:
f.replace('person', 'person_uuid')
f.set_node('person_uuid', colander.String(), missing=colander.null)
person_display = ""
if self.request.method == 'POST':
if self.request.POST.get('person_uuid'):
person = self.Session.query(model.Person)\
.get(self.request.POST['person_uuid'])
if person:
person_display = six.text_type(person)
elif self.editing:
person_display = six.text_type(order.person or "")
people_url = self.request.route_url('people.autocomplete')
f.set_widget('person_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=person_display, service_url=people_url))
f.set_label('person_uuid', "Person")
else:
f.set_renderer('person', self.render_person)

View file

@ -22,6 +22,11 @@
################################################################################
"""
Views for 'creating' customer order batches
Note that this provides only the "direct" or "raw" table views for these
batches. This does *not* provide a way to create a new batch; you should see
:meth:`tailbone.views.custorders.orders.CustomerOrdersView.create()` for that
logic.
"""
from __future__ import unicode_literals, absolute_import

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2018 Lance Edgar
# Copyright © 2010-2020 Lance Edgar
#
# This file is part of Rattail.
#
@ -43,7 +43,6 @@ class CustomerOrdersView(MasterView):
"""
model_class = model.CustomerOrder
route_prefix = 'custorders'
creatable = False
editable = False
deletable = False
@ -59,6 +58,8 @@ class CustomerOrdersView(MasterView):
'id',
'customer',
'person',
'phone_number',
'email_address',
'created',
'status_code',
]
@ -115,6 +116,130 @@ class CustomerOrdersView(MasterView):
url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url)
def create(self, form=None, template='create'):
"""
View for creating a new customer order. Note that it does so by way of
maintaining a "new customer order" batch, until the user finally
submits the order, at which point the batch is converted to a proper
order.
"""
batch = self.get_current_batch()
if self.request.method == 'POST':
# first we check for traditional form post
action = self.request.POST.get('action')
post_actions = [
'start_over_entirely',
'delete_batch',
]
if action in post_actions:
return getattr(self, action)(batch)
# okay then, we'll assume newer JSON-style post params
data = dict(self.request.json_body)
action = data.get('action')
json_actions = [
'get_customer_info',
'set_customer_data',
'submit_new_order',
]
if action in json_actions:
result = getattr(self, action)(batch, data)
return self.json_response(result)
context = {'batch': batch}
return self.render_to_response(template, context)
def get_current_batch(self):
user = self.request.user
if not user:
raise RuntimeError("this feature requires a user to be logged in")
try:
# there should be at most *one* new batch per user
batch = self.Session.query(model.CustomerOrderBatch)\
.filter(model.CustomerOrderBatch.mode == self.enum.CUSTORDER_BATCH_MODE_CREATING)\
.filter(model.CustomerOrderBatch.created_by == user)\
.one()
except orm.exc.NoResultFound:
# no batch yet for this user, so make one
batch = model.CustomerOrderBatch()
batch.mode = self.enum.CUSTORDER_BATCH_MODE_CREATING
batch.created_by = user
self.Session.add(batch)
self.Session.flush()
return batch
def start_over_entirely(self, batch):
# just delete current batch outright
# TODO: should use self.handler.do_delete() instead?
self.Session.delete(batch)
self.Session.flush()
# send user back to normal "create" page; a new batch will be generated
# for them automatically
route_prefix = self.get_route_prefix()
url = self.request.route_url('{}.create'.format(route_prefix))
return self.redirect(url)
def delete_batch(self, batch):
# just delete current batch outright
# TODO: should use self.handler.do_delete() instead?
self.Session.delete(batch)
self.Session.flush()
# set flash msg just to be more obvious
self.request.session.flash("New customer order has been deleted.")
# send user back to customer orders page, w/ no new batch generated
route_prefix = self.get_route_prefix()
url = self.request.route_url(route_prefix)
return self.redirect(url)
def get_customer_info(self, batch, data):
uuid = data.get('uuid')
if not uuid:
return {'error': "Must specify a customer UUID"}
customer = self.Session.query(model.Customer).get(uuid)
if not customer:
return {'error': "Customer not found"}
return self.info_for_customer(batch, data, customer)
def info_for_customer(self, batch, data, customer):
phone = customer.first_phone()
email = customer.first_email()
return {
'uuid': customer.uuid,
'phone_number': phone.number if phone else None,
'email_address': email.address if email else None,
}
def set_customer_data(self, batch, data):
if 'customer_uuid' in data:
batch.customer_uuid = data['customer_uuid']
if 'person_uuid' in data:
batch.person_uuid = data['person_uuid']
elif batch.customer_uuid:
self.Session.flush()
batch.person = batch.customer.first_person()
else: # no customer set
batch.person_uuid = None
if 'phone_number' in data:
batch.phone_number = data['phone_number']
if 'email_address' in data:
batch.email_address = data['email_address']
self.Session.flush()
return {'success': True}
def submit_new_order(self, batch, data):
# TODO
return {'success': True}
def includeme(config):
CustomerOrdersView.defaults(config)