Changeset - dc0c65ea7b05
[Not reviewed]
0 1 0
Lance Edgar (lance) - 3 years ago 2021-11-06 17:35:51
lance@edbob.org
Add some "case price" logic for custorder batch
1 file changed with 23 insertions and 1 deletions:
0 comments (0 inline, 0 general)
rattail/batch/custorder.py
Show inline comments
 
@@ -6,48 +6,49 @@
 
#
 
#  This file is part of Rattail.
 
#
 
#  Rattail is free software: you can redistribute it and/or modify it under the
 
#  terms of the GNU General Public License as published by the Free Software
 
#  Foundation, either version 3 of the License, or (at your option) any later
 
#  version.
 
#
 
#  Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
 
#  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
#  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
#  details.
 
#
 
#  You should have received a copy of the GNU General Public License along with
 
#  Rattail.  If not, see <http://www.gnu.org/licenses/>.
 
#
 
################################################################################
 
"""
 
Handler for "customer order" batches
 
"""
 

	
 
from __future__ import unicode_literals, absolute_import, division
 

	
 
import re
 
import decimal
 

	
 
import six
 
import sqlalchemy as sa
 
from sqlalchemy import orm
 

	
 
from rattail.db import model
 
from rattail.batch import BatchHandler
 

	
 

	
 
class CustomerOrderBatchHandler(BatchHandler):
 
    """
 
    Handler for all "customer order" batches, regardless of "mode".  The
 
    handler must inspect the
 
    :attr:`~rattail.db.model.batch.custorder.CustomerOrderBatch.mode` attribute
 
    of each batch it deals with, in order to determine which logic to apply.
 

	
 
    .. attribute:: has_custom_product_autocomplete
 

	
 
       If true, this flag indicates that the handler provides custom
 
       autocomplete logic for use when selecting a product while
 
       creating a new order.
 
    """
 
    batch_model_class = model.CustomerOrderBatch
 
    has_custom_product_autocomplete = False
 
@@ -314,48 +315,59 @@ class CustomerOrderBatchHandler(BatchHandler):
 
            pending.last_name = data['last_name']
 
        if 'display_name' in data:
 
            pending.display_name = data['display_name']
 
        else:
 
            pending.display_name = people.normalize_full_name(pending.first_name,
 
                                                              pending.last_name)
 
        if 'phone_number' in data:
 
            pending.phone_number = self.app.format_phone_number(data['phone_number'])
 
        if 'email_address' in data:
 
            pending.email_address = data['email_address']
 

	
 
        # also update the batch w/ contact info
 
        batch.contact_name = pending.display_name
 
        batch.phone_number = pending.phone_number
 
        batch.email_address = pending.email_address
 

	
 
    def get_case_size_for_product(self, product):
 
        if product.case_size:
 
            return product.case_size
 

	
 
        cost = product.cost
 
        if cost:
 
            return cost.case_size
 

	
 
    def get_case_price_for_row(self, row):
 
        """
 
        Calculate and return the per-case price for the given row.
 

	
 
        NB. we do not store case price, only unit price.  maybe that
 
        should change some day..
 
        """
 
        if row.unit_price is not None:
 
            case_price = row.unit_price * (row.case_quantity or 1)
 
            return case_price.quantize(decimal.Decimal('0.01'))
 

	
 
    # TODO: this method should maybe not exist?  and caller just
 
    # invokes the handler directly instead?
 
    def customer_autocomplete(self, session, term, **kwargs):
 
        """
 
        Override the Customer autocomplete, to search by phone number
 
        as well as name.
 
        """
 
        autocompleter = self.app.get_autocompleter('customers.neworder')
 
        return autocompleter.autocomplete(session, term, **kwargs)
 

	
 
    # TODO: this method should maybe not exist?  and caller just
 
    # invokes the handler directly instead?
 
    def person_autocomplete(self, session, term, **kwargs):
 
        """
 
        Override the Person autocomplete, to search by phone number as
 
        well as name.
 
        """
 
        autocompleter = self.app.get_autocompleter('people.neworder')
 
        return autocompleter.autocomplete(session, term, **kwargs)
 

	
 
    def get_customer_info(self, batch, **kwargs):
 
        """
 
        Return a data dict containing misc. info pertaining to the
 
        customer/person for the order batch.
 
@@ -387,54 +399,64 @@ class CustomerOrderBatchHandler(BatchHandler):
 
                    info['email_address'] = email.address
 

	
 
        return info
 

	
 
    def custom_product_autocomplete(self, session, term, **kwargs):
 
        """
 
        For the given term, this should return a (possibly empty) list
 
        of products which "match" the term.  Each element in the list
 
        should be a dict with "label" and "value" keys.
 
        """
 
        raise NotImplementedError("Please define the "
 
                                  "{}.custom_product_autocomplete() "
 
                                  "method.".format(__class__.__name__))
 

	
 
    def get_product_info(self, batch, product, **kwargs):
 
        """
 
        Return a data dict containing misc. info pertaining to the
 
        given product, for the order batch.
 
        """
 
        products = self.app.get_products_handler()
 
        info = {
 
            'uuid': product.uuid,
 
            'upc': six.text_type(product.upc),
 
            'upc_pretty': product.upc.pretty(),
 
            'unit_price_display': products.render_price(product.regular_price),
 
            'full_description': product.full_description,
 
            'size': product.size,
 
            'case_quantity': self.app.render_quantity(self.get_case_size_for_product(product)),
 
            'unit_price_display': products.render_price(product.regular_price),
 
            'image_url': products.get_image_url(product),
 
            'uom_choices': self.uom_choices_for_product(product),
 
        }
 

	
 
        case_price = None
 
        if product.regular_price and product.regular_price is not None:
 
            case_size = self.get_case_size_for_product(product)
 
            case_price = case_size * product.regular_price.price
 
            case_price = case_price.quantize(decimal.Decimal('0.01'))
 
        info['case_price'] = six.text_type(case_price) if case_price is not None else None
 
        info['case_price_display'] = self.app.render_currency(case_price)
 

	
 
        key = self.config.product_key()
 
        if key == 'upc':
 
            info['key'] = info['upc_pretty']
 
        else:
 
            info['key'] = getattr(product, key, info['upc_pretty'])
 

	
 
        return info
 

	
 
    def uom_choices_for_product(self, product):
 
        """
 
        Return a list of UOM choices for the given product.
 
        """
 
        choices = []
 

	
 
        # Each
 
        if not product or not product.weighed:
 
            unit_name = self.enum.UNIT_OF_MEASURE[self.enum.UNIT_OF_MEASURE_EACH]
 
            choices.append({'key': self.enum.UNIT_OF_MEASURE_EACH,
 
                            'value': unit_name})
 

	
 
        # Pound
 
        if not product or product.weighed:
 
            unit_name = self.enum.UNIT_OF_MEASURE[self.enum.UNIT_OF_MEASURE_POUND]
 
            choices.append({
0 comments (0 inline, 0 general)