Changeset - 1ebeac923fa0
[Not reviewed]
0 1 0
Lance Edgar (lance) - 3 years ago 2021-09-24 17:27:00
lance@edbob.org
Add "custom" customer autocomplete for new custorder handler

can search by name or phone number
1 file changed with 59 insertions and 0 deletions:
0 comments (0 inline, 0 general)
rattail/batch/custorder.py
Show inline comments
 
@@ -5,79 +5,138 @@
 
#  Copyright © 2010-2021 Lance Edgar
 
#
 
#  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 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
 
    nondigits_pattern = re.compile(r'\D')
 

	
 
    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_phone_search_term(self, term):
 
        """
 
        Try to figure out if the given search term represents a whole
 
        or partial phone number, and if so return just the digits.
 
        """
 
        digits = self.nondigits_pattern.sub('', term)
 
        if digits and len(digits) >= 4:
 
            return digits
 

	
 
    def customer_autocomplete(self, session, term, **kwargs):
 
        """
 
        Override the customer autocomplete, to search by phone number
 
        as well as customer name.
 
        """
 
        model = self.model
 

	
 
        # define the base query
 
        query = session.query(model.Customer)\
 
                       .options(orm.joinedload(model.Customer.phones))
 

	
 
        # does search term look like a phone number?
 
        phone_term = self.get_phone_search_term(term)
 
        if phone_term:
 

	
 
            # yep, so just search for the phone number
 
            query = query.join(model.CustomerPhoneNumber,
 
                               model.CustomerPhoneNumber.parent_uuid == model.Customer.uuid)
 
            query = query.filter(sa.func.regexp_replace(model.CustomerPhoneNumber.number,
 
                                                        r'\D', '', 'g')\
 
                                 .like('%{}%'.format(phone_term)))
 

	
 
        else: # term does not look like a phone number
 

	
 
            # so just search by customer name
 
            criteria = [model.Customer.name.ilike('%{}%'.format(word))
 
                        for word in term.split()]
 
            query = query.filter(sa.and_(*criteria))
 

	
 
        # oh, and sort by something useful
 
        query = query.order_by(model.Customer.name)
 

	
 
        # generate result list from query
 
        results = []
 
        for customer in query:
 
            phone = customer.first_phone()
 
            if phone:
 
                label = "{} {}".format(customer.name, phone.number)
 
            else:
 
                label = customer.name
 
            results.append({'value': customer.uuid,
 
                            'label': label,
 
                            'display': customer.name})
 

	
 
        return results
 

	
 
    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 refresh_row(self, row):
 
        if not row.product:
 
            if row.item_entry:
 
                session = orm.object_session(row)
 
                # TODO: should do more than just query for uuid here
 
                product = session.query(model.Product).get(row.item_entry)
 
                if product:
 
                    row.product = product
 
            if not row.product:
 
                row.status_code = row.STATUS_PRODUCT_NOT_FOUND
 
                return
 

	
 
        product = row.product
 
        row.product_upc = product.upc
0 comments (0 inline, 0 general)