Misc. API improvements for sake of mobile receiving
This commit is contained in:
		
							parent
							
								
									ad9c193061
								
							
						
					
					
						commit
						a721ec4a43
					
				
					 4 changed files with 74 additions and 17 deletions
				
			
		| 
						 | 
					@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue