Improve default behavior for receiving a purchase batch

only targeting desktop so far, mobile is next...
This commit is contained in:
Lance Edgar 2018-05-03 18:15:13 -05:00
parent e6144ea08b
commit a5d1eece71
3 changed files with 151 additions and 42 deletions

View file

@ -310,6 +310,17 @@ class PurchaseView(MasterView):
# department # department
f.set_renderer('department', self.render_row_department) f.set_renderer('department', self.render_row_department)
# product
f.set_renderer('product', self.render_row_product)
def render_row_product(self, row, field):
product = row.product
if not product:
return ""
text = six.text_type(product)
url = self.request.route_url('products.view', uuid=product.uuid)
return tags.link_to(text, url)
def render_row_department(self, row, field): def render_row_department(self, row, field):
return "{} {}".format(row.department_number, row.department_name) return "{} {}".format(row.department_number, row.department_name)

View file

@ -221,15 +221,24 @@ class PurchasingBatchView(BatchMasterView):
# mode # mode
f.set_enum('mode', self.enum.PURCHASE_BATCH_MODE) f.set_enum('mode', self.enum.PURCHASE_BATCH_MODE)
# TODO: this hardly seems complete...
# store # store
single_store = self.rattail_config.single_store()
if self.creating: if self.creating:
f.replace('store', 'store_uuid') f.replace('store', 'store_uuid')
f.set_widget('store_uuid', dfwidget.SelectWidget(values=self.get_store_values())) if single_store:
f.set_label('store_uuid', "Store") store = self.rattail_config.get_store(self.Session())
f.set_widget('store_uuid', forms.widgets.ReadonlyWidget())
f.set_default('store_uuid', store.uuid)
f.set_hidden('store_uuid')
else:
f.set_widget('store_uuid', dfwidget.SelectWidget(values=self.get_store_values()))
f.set_label('store_uuid', "Store")
else: else:
f.set_readonly('store') if single_store:
f.set_renderer('store', self.render_store) f.remove_field('store')
else:
f.set_readonly('store')
f.set_renderer('store', self.render_store)
# purchase # purchase
f.set_renderer('purchase', self.render_purchase) f.set_renderer('purchase', self.render_purchase)
@ -243,17 +252,27 @@ class PurchasingBatchView(BatchMasterView):
f.set_renderer('vendor', self.render_vendor) f.set_renderer('vendor', self.render_vendor)
if self.creating: if self.creating:
f.replace('vendor', 'vendor_uuid') f.replace('vendor', 'vendor_uuid')
f.set_node('vendor_uuid', colander.String())
vendor_display = ""
if self.request.method == 'POST':
if self.request.POST.get('vendor_uuid'):
vendor = self.Session.query(model.Vendor).get(self.request.POST['vendor_uuid'])
if vendor:
vendor_display = six.text_type(vendor)
vendors_url = self.request.route_url('vendors.autocomplete')
f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, service_url=vendors_url))
f.set_label('vendor_uuid', "Vendor") f.set_label('vendor_uuid', "Vendor")
widget_type = self.rattail_config.get('tailbone', 'default_widget.vendor',
default='autocomplete')
if widget_type == 'autocomplete':
vendor_display = ""
if self.request.method == 'POST':
if self.request.POST.get('vendor_uuid'):
vendor = self.Session.query(model.Vendor).get(self.request.POST['vendor_uuid'])
if vendor:
vendor_display = six.text_type(vendor)
vendors_url = self.request.route_url('vendors.autocomplete')
f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, service_url=vendors_url))
elif widget_type == 'dropdown':
vendors = self.Session.query(model.Vendor)\
.order_by(model.Vendor.id)
vendor_values = [(vendor.uuid, "({}) {}".format(vendor.id, vendor.name))
for vendor in vendors]
f.set_widget('vendor_uuid', dfwidget.SelectWidget(values=vendor_values))
else:
raise NotImplementedError("Unsupported vendor widget type: {}".format(widget_type))
elif self.editing: elif self.editing:
f.set_readonly('vendor') f.set_readonly('vendor')
@ -271,26 +290,27 @@ class PurchasingBatchView(BatchMasterView):
f.set_readonly('department') f.set_readonly('department')
# buyer # buyer
f.set_renderer('buyer', self.render_buyer) if 'buyer' in f:
if self.creating or self.editing: f.set_renderer('buyer', self.render_buyer)
f.replace('buyer', 'buyer_uuid') if self.creating or self.editing:
f.set_node('buyer_uuid', colander.String(), missing=colander.null) f.replace('buyer', 'buyer_uuid')
buyer_display = "" f.set_node('buyer_uuid', colander.String(), missing=colander.null)
if self.request.method == 'POST': buyer_display = ""
if self.request.POST.get('buyer_uuid'): if self.request.method == 'POST':
buyer = self.Session.query(model.Employee).get(self.request.POST['buyer_uuid']) if self.request.POST.get('buyer_uuid'):
if buyer: buyer = self.Session.query(model.Employee).get(self.request.POST['buyer_uuid'])
buyer_display = six.text_type(buyer) if buyer:
elif self.creating: buyer_display = six.text_type(buyer)
buyer = self.request.user.employee elif self.creating:
buyer_display = six.text_type(buyer) buyer = self.request.user.employee
f.set_default('buyer_uuid', buyer.uuid) buyer_display = six.text_type(buyer)
elif self.editing: f.set_default('buyer_uuid', buyer.uuid)
buyer_display = six.text_type(batch.buyer or '') elif self.editing:
buyers_url = self.request.route_url('employees.autocomplete') buyer_display = six.text_type(batch.buyer or '')
f.set_widget('buyer_uuid', forms.widgets.JQueryAutocompleteWidget( buyers_url = self.request.route_url('employees.autocomplete')
field_display=buyer_display, service_url=buyers_url)) f.set_widget('buyer_uuid', forms.widgets.JQueryAutocompleteWidget(
f.set_label('buyer_uuid', "Buyer") field_display=buyer_display, service_url=buyers_url))
f.set_label('buyer_uuid', "Buyer")
# date_ordered # date_ordered
f.set_type('date_ordered', 'date_jquery') f.set_type('date_ordered', 'date_jquery')
@ -629,19 +649,33 @@ class PurchasingBatchView(BatchMasterView):
elif self.editing: elif self.editing:
f.set_readonly('upc') f.set_readonly('upc')
f.set_readonly('item_id')
f.set_readonly('product') f.set_readonly('product')
f.remove_fields('po_total', f.set_renderer('product', self.render_product)
'invoice_total',
'status_code') # TODO: what's up with this again?
# f.remove_fields('po_total',
# 'invoice_total',
# 'status_code')
elif self.viewing: elif self.viewing:
if row.product: if row.product:
f.remove_fields('brand_name', f.remove_fields('brand_name',
'description', 'description',
'size') 'size')
f.set_renderer('product', self.render_row_product)
else: else:
f.remove_field('product') f.remove_field('product')
def render_row_product(self, row, field):
product = row.product
if not product:
return ""
text = six.text_type(product)
url = self.request.route_url('products.view', uuid=product.uuid)
return tags.link_to(text, url)
def configure_mobile_row_form(self, f): def configure_mobile_row_form(self, f):
super(PurchasingBatchView, self).configure_mobile_row_form(f) super(PurchasingBatchView, self).configure_mobile_row_form(f)
# row = f.model_instance # row = f.model_instance
@ -786,6 +820,11 @@ class PurchasingBatchView(BatchMasterView):
# self.request.session.flash("Added item: {} {}".format(row.upc.pretty(), row.product)) # self.request.session.flash("Added item: {} {}".format(row.upc.pretty(), row.product))
# return self.redirect(self.request.current_route_url()) # return self.redirect(self.request.current_route_url())
# TODO: seems like this should be master behavior, controlled by setting?
def redirect_after_edit_row(self, row, mobile=False):
parent = self.get_parent(row)
return self.redirect(self.get_action_url('view', parent, mobile=mobile))
def delete_row(self): def delete_row(self):
""" """
Update the batch totals in addition to marking row as removed. Update the batch totals in addition to marking row as removed.

View file

@ -89,11 +89,38 @@ class ReceivingBatchView(PurchasingBatchView):
model_title_plural = "Receiving Batches" model_title_plural = "Receiving Batches"
index_title = "Receiving" index_title = "Receiving"
creatable = False creatable = False
rows_editable = True
rows_deletable = False rows_deletable = False
mobile_creatable = True mobile_creatable = True
mobile_rows_filterable = True mobile_rows_filterable = True
mobile_rows_creatable = True mobile_rows_creatable = True
form_fields = [
'id',
'store',
'vendor',
'department',
'purchase',
'vendor_email',
'vendor_fax',
'vendor_contact',
'vendor_phone',
'date_ordered',
'date_received',
'po_number',
'po_total',
'invoice_date',
'invoice_number',
'invoice_total',
'notes',
'created',
'created_by',
'status_code',
'complete',
'executed',
'executed_by',
]
mobile_form_fields = [ mobile_form_fields = [
'vendor', 'vendor',
'department', 'department',
@ -116,6 +143,34 @@ class ReceivingBatchView(PurchasingBatchView):
'status_code', 'status_code',
] ]
row_form_fields = [
'upc',
'item_id',
'product',
'brand_name',
'description',
'size',
'case_quantity',
'cases_ordered',
'units_ordered',
'cases_received',
'units_received',
'cases_damaged',
'units_damaged',
'cases_expired',
'units_expired',
'cases_mispick',
'units_mispick',
'po_line_number',
'po_unit_cost',
'po_total',
'invoice_line_number',
'invoice_unit_cost',
'invoice_total',
'status_code',
'credits',
]
@property @property
def batch_mode(self): def batch_mode(self):
return self.enum.PURCHASE_BATCH_MODE_RECEIVING return self.enum.PURCHASE_BATCH_MODE_RECEIVING
@ -177,8 +232,6 @@ class ReceivingBatchView(PurchasingBatchView):
if mobile: if mobile:
purchase = self.get_purchase(self.request.POST['purchase']) purchase = self.get_purchase(self.request.POST['purchase'])
kwargs['sms_transaction_number'] = purchase.F1032
numbers = [d.F03 for d in purchase.details] numbers = [d.F03 for d in purchase.details]
if numbers: if numbers:
number = max(set(numbers), key=numbers.count) number = max(set(numbers), key=numbers.count)
@ -186,8 +239,6 @@ class ReceivingBatchView(PurchasingBatchView):
.filter(model.Department.number == number)\ .filter(model.Department.number == number)\
.one() .one()
else:
kwargs['sms_transaction_number'] = batch.sms_transaction_number
return kwargs return kwargs
def configure_mobile_form(self, f): def configure_mobile_form(self, f):
@ -199,6 +250,14 @@ class ReceivingBatchView(PurchasingBatchView):
# department # department
# fs.department.with_renderer(fa.TextFieldRenderer), # fs.department.with_renderer(fa.TextFieldRenderer),
def configure_row_form(self, f):
super(ReceivingBatchView, self).configure_row_form(f)
f.set_readonly('cases_ordered')
f.set_readonly('units_ordered')
f.set_readonly('po_unit_cost')
f.set_readonly('po_total')
f.set_readonly('invoice_total')
def render_mobile_row_listitem(self, row, i): def render_mobile_row_listitem(self, row, i):
description = row.product.full_description if row.product else row.description description = row.product.full_description if row.product else row.description
return "({}) {}".format(row.upc.pretty(), description) return "({}) {}".format(row.upc.pretty(), description)