Misc. API improvements for sake of mobile receiving
This commit is contained in:
parent
ad9c193061
commit
a721ec4a43
|
@ -107,6 +107,9 @@ class APIBatchView(APIBatchMixin, APIMasterView):
|
||||||
'created_by_uuid': batch.created_by.uuid,
|
'created_by_uuid': batch.created_by.uuid,
|
||||||
'created_by_display': six.text_type(batch.created_by),
|
'created_by_display': six.text_type(batch.created_by),
|
||||||
'complete': batch.complete,
|
'complete': batch.complete,
|
||||||
|
'status_code': batch.status_code,
|
||||||
|
'status_display': batch.STATUS.get(batch.status_code,
|
||||||
|
six.text_type(batch.status_code)),
|
||||||
'executed': executed,
|
'executed': executed,
|
||||||
'executed_by_uuid': batch.executed_by_uuid,
|
'executed_by_uuid': batch.executed_by_uuid,
|
||||||
'executed_by_display': six.text_type(batch.executed_by or ''),
|
'executed_by_display': six.text_type(batch.executed_by or ''),
|
||||||
|
|
|
@ -34,6 +34,7 @@ import humanize
|
||||||
from rattail import pod
|
from rattail import pod
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
from rattail.time import make_utc
|
from rattail.time import make_utc
|
||||||
|
from rattail.util import pretty_quantity
|
||||||
|
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
|
|
||||||
|
@ -54,6 +55,7 @@ class ReceivingBatchViews(APIBatchView):
|
||||||
collection_url_prefix = '/receiving-batches'
|
collection_url_prefix = '/receiving-batches'
|
||||||
object_url_prefix = '/receiving-batch'
|
object_url_prefix = '/receiving-batch'
|
||||||
supports_toggle_complete = True
|
supports_toggle_complete = True
|
||||||
|
supports_execute = True
|
||||||
|
|
||||||
def base_query(self):
|
def base_query(self):
|
||||||
query = super(ReceivingBatchViews, self).base_query()
|
query = super(ReceivingBatchViews, self).base_query()
|
||||||
|
@ -69,20 +71,15 @@ class ReceivingBatchViews(APIBatchView):
|
||||||
data['department_uuid'] = batch.department_uuid
|
data['department_uuid'] = batch.department_uuid
|
||||||
data['department_display'] = six.text_type(batch.department) if batch.department else None
|
data['department_display'] = six.text_type(batch.department) if batch.department else None
|
||||||
|
|
||||||
return data
|
data['po_total'] = batch.po_total
|
||||||
|
data['invoice_total'] = batch.invoice_total
|
||||||
|
data['invoice_total_calculated'] = batch.invoice_total_calculated
|
||||||
|
|
||||||
def get_purchase(self, uuid):
|
return data
|
||||||
return self.Session.query(model.Purchase).get(uuid)
|
|
||||||
|
|
||||||
def create_object(self, data):
|
def create_object(self, data):
|
||||||
data = dict(data)
|
data = dict(data)
|
||||||
|
|
||||||
data['mode'] = self.enum.PURCHASE_BATCH_MODE_RECEIVING
|
data['mode'] = self.enum.PURCHASE_BATCH_MODE_RECEIVING
|
||||||
|
|
||||||
# if 'purchase_key' in data:
|
|
||||||
# purchase = self.get_purchase(data['purchase_key'])
|
|
||||||
# data['purchase'] = purchase
|
|
||||||
|
|
||||||
batch = super(ReceivingBatchViews, self).create_object(data)
|
batch = super(ReceivingBatchViews, self).create_object(data)
|
||||||
return batch
|
return batch
|
||||||
|
|
||||||
|
@ -135,7 +132,7 @@ class ReceivingBatchViews(APIBatchView):
|
||||||
elif purchase.status == self.enum.PURCHASE_STATUS_RECEIVED:
|
elif purchase.status == self.enum.PURCHASE_STATUS_RECEIVED:
|
||||||
date = purchase.date_received
|
date = purchase.date_received
|
||||||
total = purchase.invoice_total
|
total = purchase.invoice_total
|
||||||
return '{} for ${:0,.2f} ({})'.format(date, total, purchase.department or purchase.buyer)
|
return '{} for ${:0,.2f} ({})'.format(date, total or 0, purchase.department or purchase.buyer)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def defaults(cls, config):
|
def defaults(cls, config):
|
||||||
|
@ -241,6 +238,15 @@ class ReceivingBatchRowViews(APIBatchRowView):
|
||||||
{'field': 'units_shipped', 'op': 'is_null'},
|
{'field': 'units_shipped', 'op': 'is_null'},
|
||||||
{'field': 'units_shipped', 'op': '==', 'value': 0},
|
{'field': 'units_shipped', 'op': '==', 'value': 0},
|
||||||
]},
|
]},
|
||||||
|
{'or': [
|
||||||
|
# but "unexpected" also implies we have some confirmed amount(s)
|
||||||
|
{'field': 'cases_received', 'op': '!=', 'value': 0},
|
||||||
|
{'field': 'units_received', 'op': '!=', 'value': 0},
|
||||||
|
{'field': 'cases_damaged', 'op': '!=', 'value': 0},
|
||||||
|
{'field': 'units_damaged', 'op': '!=', 'value': 0},
|
||||||
|
{'field': 'cases_expired', 'op': '!=', 'value': 0},
|
||||||
|
{'field': 'units_expired', 'op': '!=', 'value': 0},
|
||||||
|
]},
|
||||||
]},
|
]},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -271,6 +277,7 @@ class ReceivingBatchRowViews(APIBatchRowView):
|
||||||
batch = row.batch
|
batch = row.batch
|
||||||
data = super(ReceivingBatchRowViews, self).normalize(row)
|
data = super(ReceivingBatchRowViews, self).normalize(row)
|
||||||
|
|
||||||
|
data['product_uuid'] = row.product_uuid
|
||||||
data['item_id'] = row.item_id
|
data['item_id'] = row.item_id
|
||||||
data['upc'] = six.text_type(row.upc)
|
data['upc'] = six.text_type(row.upc)
|
||||||
data['upc_pretty'] = row.upc.pretty() if row.upc else None
|
data['upc_pretty'] = row.upc.pretty() if row.upc else None
|
||||||
|
@ -304,6 +311,53 @@ class ReceivingBatchRowViews(APIBatchRowView):
|
||||||
data['cases_expired'] = row.cases_expired
|
data['cases_expired'] = row.cases_expired
|
||||||
data['units_expired'] = row.units_expired
|
data['units_expired'] = row.units_expired
|
||||||
|
|
||||||
|
data['po_unit_cost'] = row.po_unit_cost
|
||||||
|
data['po_total'] = row.po_total
|
||||||
|
|
||||||
|
data['invoice_unit_cost'] = row.invoice_unit_cost
|
||||||
|
data['invoice_total'] = row.invoice_total
|
||||||
|
data['invoice_total_calculated'] = row.invoice_total_calculated
|
||||||
|
|
||||||
|
data['allow_cases'] = self.handler.allow_cases()
|
||||||
|
|
||||||
|
data['quick_receive'] = self.rattail_config.getbool(
|
||||||
|
'rattail.batch', 'purchase.mobile_quick_receive',
|
||||||
|
default=True)
|
||||||
|
|
||||||
|
if batch.order_quantities_known:
|
||||||
|
data['quick_receive_all'] = self.rattail_config.getbool(
|
||||||
|
'rattail.batch', 'purchase.mobile_quick_receive_all',
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
# TODO: this was copied from regular view receive_row() method; should merge
|
||||||
|
if data['quick_receive'] and data.get('quick_receive_all'):
|
||||||
|
if data['allow_cases']:
|
||||||
|
data['quick_receive_uom'] = 'CS'
|
||||||
|
raise NotImplementedError("TODO: add CS support for quick_receive_all")
|
||||||
|
else:
|
||||||
|
data['quick_receive_uom'] = data['unit_uom']
|
||||||
|
accounted_for = self.handler.get_units_accounted_for(row)
|
||||||
|
remainder = self.handler.get_units_ordered(row) - accounted_for
|
||||||
|
|
||||||
|
if accounted_for:
|
||||||
|
# some product accounted for; button should receive "remainder" only
|
||||||
|
if remainder:
|
||||||
|
remainder = pretty_quantity(remainder)
|
||||||
|
data['quick_receive_quantity'] = remainder
|
||||||
|
data['quick_receive_text'] = "Receive Remainder ({} {})".format(
|
||||||
|
remainder, data['unit_uom'])
|
||||||
|
else:
|
||||||
|
# unless there is no remainder, in which case disable it
|
||||||
|
data['quick_receive'] = False
|
||||||
|
|
||||||
|
else: # nothing yet accounted for, button should receive "all"
|
||||||
|
if not remainder:
|
||||||
|
log.warning("quick receive remainder is empty for row %s", row.uuid)
|
||||||
|
remainder = pretty_quantity(remainder)
|
||||||
|
data['quick_receive_quantity'] = remainder
|
||||||
|
data['quick_receive_text'] = "Receive ALL ({} {})".format(
|
||||||
|
remainder, data['unit_uom'])
|
||||||
|
|
||||||
data['unexpected_alert'] = None
|
data['unexpected_alert'] = None
|
||||||
if batch.order_quantities_known and not row.cases_ordered and not row.units_ordered:
|
if batch.order_quantities_known and not row.cases_ordered and not row.units_ordered:
|
||||||
warn = True
|
warn = True
|
||||||
|
|
|
@ -285,7 +285,8 @@
|
||||||
|
|
||||||
<%def name="object_helpers()">
|
<%def name="object_helpers()">
|
||||||
${parent.object_helpers()}
|
${parent.object_helpers()}
|
||||||
% if not request.rattail_config.production():
|
## TODO: for now this is a truck-dump-only feature? maybe should change that
|
||||||
|
% if not request.rattail_config.production() and master.allow_truck_dump:
|
||||||
% if not batch.executed and not batch.complete and request.has_perm('admin'):
|
% if not batch.executed and not batch.complete and request.has_perm('admin'):
|
||||||
% if (batch.is_truck_dump_parent() and batch.truck_dump_children_first) or not batch.is_truck_dump_related():
|
% if (batch.is_truck_dump_parent() and batch.truck_dump_children_first) or not batch.is_truck_dump_related():
|
||||||
<div class="object-helper">
|
<div class="object-helper">
|
||||||
|
|
|
@ -130,6 +130,7 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
model_title_plural = "Receiving Batches"
|
model_title_plural = "Receiving Batches"
|
||||||
index_title = "Receiving"
|
index_title = "Receiving"
|
||||||
downloadable = True
|
downloadable = True
|
||||||
|
bulk_deletable = True
|
||||||
rows_editable = True
|
rows_editable = True
|
||||||
mobile_creatable = True
|
mobile_creatable = True
|
||||||
mobile_rows_filterable = True
|
mobile_rows_filterable = True
|
||||||
|
@ -200,6 +201,7 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
'truck_dump_status',
|
'truck_dump_status',
|
||||||
'rowcount',
|
'rowcount',
|
||||||
'order_quantities_known',
|
'order_quantities_known',
|
||||||
|
'receiving_complete',
|
||||||
'complete',
|
'complete',
|
||||||
'executed',
|
'executed',
|
||||||
'executed_by',
|
'executed_by',
|
||||||
|
@ -639,9 +641,6 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
default_value=default_status)
|
default_value=default_status)
|
||||||
return filters
|
return filters
|
||||||
|
|
||||||
def get_purchase(self, uuid):
|
|
||||||
return self.Session.query(model.Purchase).get(uuid)
|
|
||||||
|
|
||||||
def mobile_create(self):
|
def mobile_create(self):
|
||||||
"""
|
"""
|
||||||
Mobile view for creating a new receiving batch
|
Mobile view for creating a new receiving batch
|
||||||
|
@ -759,9 +758,9 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
Assign the original purchase order to the given batch. Default
|
Assign the original purchase order to the given batch. Default
|
||||||
behavior assumes a Rattail Purchase object is what we're after.
|
behavior assumes a Rattail Purchase object is what we're after.
|
||||||
"""
|
"""
|
||||||
purchase = self.get_purchase(po_form.validated[self.purchase_order_fieldname])
|
purchase = self.handler.assign_purchase_order(
|
||||||
if isinstance(purchase, model.Purchase):
|
batch, po_form.validated[self.purchase_order_fieldname],
|
||||||
batch.purchase_uuid = purchase.uuid
|
session=self.Session())
|
||||||
|
|
||||||
department = self.department_for_purchase(purchase)
|
department = self.department_for_purchase(purchase)
|
||||||
if department:
|
if department:
|
||||||
|
|
Loading…
Reference in a new issue