Add (restore?) basic support for mobile receiving from PO

This commit is contained in:
Lance Edgar 2018-07-18 16:25:54 -05:00
parent 87ba8026e5
commit 34bdd2ac84
5 changed files with 122 additions and 67 deletions

View file

@ -560,9 +560,11 @@ class PurchasingBatchView(BatchMasterView):
if self.batch_mode in (self.enum.PURCHASE_BATCH_MODE_RECEIVING,
self.enum.PURCHASE_BATCH_MODE_COSTING):
if batch.purchase_uuid:
purchase = batch.purchase
if not purchase and batch.purchase_uuid:
purchase = self.Session.query(model.Purchase).get(batch.purchase_uuid)
assert purchase
if purchase:
kwargs['purchase'] = purchase
kwargs['buyer'] = purchase.buyer
kwargs['buyer_uuid'] = purchase.buyer_uuid

View file

@ -66,8 +66,19 @@ class MobileItemStatusFilter(grids.filters.MobileFilter):
# TODO: is this accurate (enough) ?
if value == 'incomplete':
return query.filter(sa.or_(model.PurchaseBatchRow.cases_ordered != 0, model.PurchaseBatchRow.units_ordered != 0))\
.filter(model.PurchaseBatchRow.status_code != model.PurchaseBatchRow.STATUS_OK)
return query.filter(sa.or_(model.PurchaseBatchRow.cases_ordered != 0,
model.PurchaseBatchRow.units_ordered != 0))\
.filter(~model.PurchaseBatchRow.status_code.in_((
model.PurchaseBatchRow.STATUS_OK,
model.PurchaseBatchRow.STATUS_PRODUCT_NOT_FOUND)))
if value == 'invalid':
return query.filter(model.PurchaseBatchRow.status_code.in_((
model.PurchaseBatchRow.STATUS_PRODUCT_NOT_FOUND,
model.PurchaseBatchRow.STATUS_COST_NOT_FOUND,
model.PurchaseBatchRow.STATUS_CASE_QUANTITY_UNKNOWN,
model.PurchaseBatchRow.STATUS_CASE_QUANTITY_DIFFERS,
)))
if value == 'unexpected':
return query.filter(sa.and_(
@ -118,6 +129,8 @@ class ReceivingBatchView(PurchasingBatchView):
default_uom_is_case = True
purchase_order_fieldname = 'purchase'
labels = {
'truck_dump_batch': "Truck Dump Parent",
'invoice_parser_key': "Invoice Parser",
@ -363,18 +376,7 @@ class ReceivingBatchView(PurchasingBatchView):
def get_batch_kwargs(self, batch, mobile=False):
kwargs = super(ReceivingBatchView, self).get_batch_kwargs(batch, mobile=mobile)
if mobile:
if 'purchase' in self.request.POST:
purchase = self.get_purchase(self.request.POST['purchase'])
if isinstance(purchase, model.Purchase):
kwargs['purchase'] = purchase
department = self.department_for_purchase(purchase)
if department:
kwargs['department'] = department
else: # not mobile
if not mobile:
batch_type = self.request.POST['batch_type']
if batch_type == 'from_scratch':
kwargs.pop('truck_dump_batch', None)
@ -516,10 +518,10 @@ class ReceivingBatchView(PurchasingBatchView):
# visible filter options will depend on whether batch came from purchase
if batch.order_quantities_known:
value_choices = ['incomplete', 'unexpected', 'damaged', 'expired', 'all']
value_choices = ['incomplete', 'unexpected', 'damaged', 'expired', 'invalid', 'all']
default_status = 'incomplete'
else:
value_choices = ['received', 'damaged', 'expired', 'all']
value_choices = ['received', 'damaged', 'expired', 'invalid', 'all']
default_status = 'all'
# remove 'expired' filter option if not relevant
@ -540,10 +542,12 @@ class ReceivingBatchView(PurchasingBatchView):
"""
mode = self.batch_mode
data = {'mode': mode}
phase = 1
schema = MobileNewReceivingBatch().bind(session=self.Session())
form = forms.Form(schema=schema, request=self.request)
if form.validate(newstyle=True):
phase = form.validated['phase']
if form.validated['workflow'] == 'from_scratch':
if not self.allow_from_scratch:
@ -556,7 +560,7 @@ class ReceivingBatchView(PurchasingBatchView):
batch.date_received = localtime(self.rattail_config).date()
kwargs = self.get_batch_kwargs(batch, mobile=True)
batch = self.handler.make_batch(self.Session(), **kwargs)
return self.redirect(self.request.route_url('mobile.receiving.view', uuid=batch.uuid))
return self.redirect(self.get_action_url('view', batch, mobile=True))
elif form.validated['workflow'] == 'truck_dump':
if not self.allow_truck_dump:
@ -565,44 +569,85 @@ class ReceivingBatchView(PurchasingBatchView):
batch.store = self.rattail_config.get_store(self.Session())
batch.mode = mode
batch.truck_dump = True
batch.vendor = self.Session.merge(form.validated['vendor'])
batch.vendor = self.Session.query(model.Vendor).get(form.validated['vendor'])
batch.created_by = self.request.user
batch.date_received = localtime(self.rattail_config).date()
kwargs = self.get_batch_kwargs(batch, mobile=True)
batch = self.handler.make_batch(self.Session(), **kwargs)
return self.redirect(self.request.route_url('mobile.receiving.view', uuid=batch.uuid))
return self.redirect(self.get_action_url('view', batch, mobile=True))
else:
raise NotImplementedError("Requested workflow not supported: {}".format(form.validated['workflow']))
elif form.validated['workflow'] == 'from_po':
if not self.allow_from_po:
raise NotImplementedError("Requested workflow not supported: from_po")
vendor = None
if self.request.method == 'POST' and self.request.POST.get('vendor'):
vendor = self.Session.query(model.Vendor).get(self.request.POST['vendor'])
if vendor:
vendor = self.Session.query(model.Vendor).get(form.validated['vendor'])
data['vendor'] = vendor
if self.request.POST.get('purchase'):
purchase = self.get_purchase(self.request.POST['purchase'])
if purchase:
schema = self.make_mobile_receiving_from_po_schema()
po_form = forms.Form(schema=schema, request=self.request)
if phase == 2:
if po_form.validate(newstyle=True):
batch = self.model_class()
batch.store = self.rattail_config.get_store(self.Session())
batch.mode = mode
batch.vendor = vendor
batch.store = self.rattail_config.get_store(self.Session())
batch.buyer = self.request.user.employee
batch.created_by = self.request.user
batch.date_received = localtime(self.rattail_config).date()
self.assign_purchase_order(batch, po_form)
kwargs = self.get_batch_kwargs(batch, mobile=True)
batch = self.handler.make_batch(self.Session(), **kwargs)
if self.handler.should_populate(batch):
self.handler.populate(batch)
return self.redirect(self.request.route_url('mobile.receiving.view', uuid=batch.uuid))
return self.redirect(self.get_action_url('view', batch, mobile=True))
else:
phase = 2
else:
raise NotImplementedError("Requested workflow not supported: {}".format(form.validated['workflow']))
data['form'] = form
data['dform'] = form.make_deform_form()
data['mode_title'] = self.enum.PURCHASE_BATCH_MODE[mode].capitalize()
if vendor:
data['phase'] = phase
if phase == 2:
purchases = self.eligible_purchases(vendor.uuid, mode=mode)
data['purchases'] = [(p['key'], p['display']) for p in purchases['purchases']]
data['purchase_order_fieldname'] = self.purchase_order_fieldname
return self.render_to_response('create', data, mobile=True)
def make_mobile_receiving_from_po_schema(self):
schema = colander.MappingSchema()
schema.add(colander.SchemaNode(colander.String(),
name=self.purchase_order_fieldname,
validator=self.validate_purchase))
return schema.bind(session=self.Session())
@staticmethod
@colander.deferred
def validate_purchase(node, kw):
session = kw['session']
def validate(node, value):
purchase = session.query(model.Purchase).get(value)
if not purchase:
raise colander.Invalid(node, "Purchase not found")
return purchase.uuid
return validate
def assign_purchase_order(self, batch, po_form):
"""
Assign the original purchase order to the given batch. Default
behavior assumes a Rattail Purchase object is what we're after.
"""
purchase = self.get_purchase(po_form.validated[self.purchase_order_fieldname])
if isinstance(purchase, model.Purchase):
batch.purchase = purchase
department = self.department_for_purchase(purchase)
if department:
batch.department = department
def configure_mobile_form(self, f):
super(ReceivingBatchView, self).configure_mobile_form(f)
batch = f.model_instance
@ -950,6 +995,13 @@ class MobileNewReceivingBatch(colander.MappingSchema):
'truck_dump',
]))
phase = colander.SchemaNode(colander.Int())
class MobileNewReceivingFromPO(colander.MappingSchema):
purchase = colander.SchemaNode(colander.String())
# TODO: this is a stopgap measure to fix an obvious bug, which exists when the
# session is not provided by the view at runtime (i.e. when it was instead