Changeset - 3d89915d9459
[Not reviewed]
0 3 2
Lance Edgar (lance) - 3 years ago 2021-10-06 13:47:07
lance@edbob.org
Add "contact update request" workflow for new custorders

if user requests contact info be updated on the customer record, then
"someone" (staff) should receive an email with that info
5 files changed with 189 insertions and 31 deletions:
0 comments (0 inline, 0 general)
rattail/batch/custorder.py
Show inline comments
 
@@ -123,42 +123,57 @@ class CustomerOrderBatchHandler(BatchHandler):
 
            batch.phone_number = clientele.get_first_phone_number(customer)
 
            batch.email_address = clientele.get_first_email_address(customer)
 
        else:
 
            batch.phone_number = person.first_phone_number()
 
            batch.email_address = person.first_email_address()
 

	
 
        # always reset "add to customer" flags
 
        batch.clear_param('add_phone_number')
 
        batch.clear_param('add_email_address')
 

	
 
        session = self.app.get_session(batch)
 
        session.flush()
 

	
 
    def get_contact_display(self, batch):
 
    def get_contact(self, batch):
 
        """
 
        Should return contact display text for the batch,
 
        i.e. customer name.
 
        Should return the contact record (i.e. Customer or Person) for
 
        the batch.
 
        """
 
        customer_required = self.new_order_requires_customer()
 

	
 
        if customer_required:
 
            return six.text_type(batch.customer)
 
            return batch.customer
 
        else:
 
            return six.text_type(batch.person)
 
            return batch.person
 

	
 
    def get_contact_id(self, batch):
 
        """
 
        Should return contact ID for the batch, i.e. customer ID.
 
        """
 
        contact = self.get_contact(batch)
 
        if isinstance(contact, model.Customer):
 
            return contact.id
 

	
 
    def get_contact_display(self, batch):
 
        """
 
        Should return contact display text for the batch,
 
        i.e. customer name.
 
        """
 
        contact = self.get_contact(batch)
 
        return six.text_type(contact)
 

	
 
    def get_contact_phones(self, batch):
 
        """
 
        Retrieve all phone records on file for the batch contact, to
 
        be presented as options for user to choose from when making a
 
        new order.
 
        """
 
        customer_required = self.new_order_requires_customer()
 

	
 
        phones = []
 
        if customer_required:
 
            if batch.customer:
 
                phones = batch.customer.phones
 
        else:
 
            if batch.person:
 
                phones = batch.person.phones
 
        contact = self.get_contact(batch)
 
        if contact:
 
            phones = contact.phones
 

	
 
        return [self.normalize_phone(phone)
 
                for phone in phones]
 

	
 
    def normalize_phone(self, phone):
 
        """
 
@@ -178,21 +193,16 @@ class CustomerOrderBatchHandler(BatchHandler):
 
        Retrieve all email records on file for the batch contact, to
 
        be presented as options for user to choose from when making a
 
        new order.
 

	
 
        Note that the default logic will exclude invalid email addresses.
 
        """
 
        customer_required = self.new_order_requires_customer()
 

	
 
        emails = []
 
        if customer_required:
 
            if batch.customer:
 
                emails = batch.customer.emails
 
        else:
 
            if batch.person:
 
                emails = batch.person.emails
 
        contact = self.get_contact(batch)
 
        if contact:
 
            emails = contact.emails
 

	
 
        # exclude invalid
 
        emails = [email for email in emails
 
                  if not email.invalid]
 

	
 
        return [self.normalize_email(email)
 
@@ -215,22 +225,17 @@ class CustomerOrderBatchHandler(BatchHandler):
 
    def get_contact_notes(self, batch):
 
        """
 
        Get extra "contact notes" which should be made visible to the
 
        user who is entering the new order.
 
        """
 
        notes = []
 
        customer_required = self.new_order_requires_customer()
 

	
 
        invalid = False
 
        if customer_required:
 
            if batch.customer:
 
                invalid = [email for email in batch.customer.emails
 
                           if email.invalid]
 
        else:
 
            if batch.person:
 
                invalid = [email for email in batch.person.emails
 
        contact = self.get_contact(batch)
 
        if contact:
 
            invalid = [email for email in contact.emails
 
                       if email.invalid]
 
        if invalid:
 
            notes.append("Customer has one or more invalid email addresses on file.")
 

	
 
        return notes
 

	
 
@@ -240,12 +245,16 @@ class CustomerOrderBatchHandler(BatchHandler):
 
        """
 
        batch.customer = None
 
        batch.person = None
 
        batch.phone_number = None
 
        batch.email_address = None
 

	
 
        # always reset "add to customer" flags
 
        batch.clear_param('add_phone_number')
 
        batch.clear_param('add_email_address')
 

	
 
        session = self.app.get_session(batch)
 
        session.flush()
 
        session.refresh(batch)
 

	
 
    def get_case_size_for_product(self, product):
 
        if product.case_size:
 
@@ -461,14 +470,65 @@ class CustomerOrderBatchHandler(BatchHandler):
 
                batch.total_price = (batch.total_price or 0) - row.total_price
 

	
 
        self.refresh_batch_status(batch)
 

	
 
    def execute(self, batch, user=None, progress=None, **kwargs):
 
        """
 
        Default behavior here will simply create a new (proper) Customer Order
 
        based on the batch contents.  Override as needed.
 
        Default behavior here will create and return a new rattail
 
        Customer Order.  It also may "add contact info" e.g. to the
 
        customer record.  Override as needed.
 
        """
 
        order = self.make_new_order(batch, user=user, progress=progress, **kwargs)
 
        self.update_contact_info(batch, user)
 
        return order
 

	
 
    def update_contact_info(self, batch, user, **kwargs):
 
        """
 
        Update contact info from the batch, onto the customer record.
 
        """
 
        if batch.get_param('add_phone_number'):
 
            self.add_phone_number(batch, user)
 
        if batch.get_param('add_email_address'):
 
            self.add_email_address(batch, user)
 

	
 
    def add_phone_number(self, batch, user, **kwargs):
 
        """
 
        Add phone number from the batch to the customer record.
 

	
 
        Note that the default behavior does *not* do that, but instead
 
        will send an email alert to configured recipient(s) with the
 
        update request.
 
        """
 
        self.app.send_email('new_phone_requested', {
 
            'user': user,
 
            'user_display': user.display_name if user else "(unknown user)",
 
            'contact': self.get_contact(batch),
 
            'contact_id': self.get_contact_id(batch),
 
            'phone_number': batch.phone_number,
 
        })
 

	
 
    def add_email_address(self, batch, user, **kwargs):
 
        """
 
        Add email address from the batch to the customer record.
 

	
 
        Note that the default behavior does *not* do that, but instead
 
        will send an email alert to configured recipient(s) with the
 
        update request.
 
        """
 
        self.app.send_email('new_email_requested', {
 
            'user': user,
 
            'user_display': user.display_name if user else "(unknown user)",
 
            'contact': self.get_contact(batch),
 
            'contact_id': self.get_contact_id(batch),
 
            'email_address': batch.email_address,
 
        })
 

	
 
    def make_new_order(self, batch, user=None, progress=None, **kwargs):
 
        """
 
        Create and return a new rattail Customer Order based on the
 
        batch contents.
 
        """
 
        batch_fields = [
 
            'store',
 
            'id',
 
            'customer',
 
            'person',
rattail/db/model/batch/core.py
Show inline comments
 
@@ -195,12 +195,30 @@ class BatchMixin(object):
 

	
 
    def __str__(self):
 
        return "{} {}".format(
 
            self.__class__.__name__,
 
            self.id_str if self.id else "(new)")
 

	
 
    def get_param(self, key):
 
        if self.params is not None:
 
            return self.params.get(key)
 

	
 
    def set_param(self, key, value):
 
        # TODO: why must we reconstruct params each time instead of
 
        # just modifying in place?
 
        params = dict(self.params or {})
 
        params[key] = value
 
        self.params = params
 

	
 
    def clear_param(self, key):
 
        # TODO: why must we reconstruct params each time instead of
 
        # just modifying in place?
 
        params = dict(self.params or {})
 
        params.pop(key, None)
 
        self.params = params
 

	
 
    # TODO: deprecate/remove this?
 
    def add_row(self, row):
 
        """
 
        Convenience method for appending a data row, with auto-sequence.
 
        """
 
        self.data_rows.append(row)
rattail/emails.py
Show inline comments
 
@@ -143,12 +143,50 @@ class filemon_action_error(Email):
 
            'attempts': 3,
 
            'error': exc,
 
            'traceback': ''.join(format_exception(exc_type, exc, traceback)).strip(),
 
        }
 

	
 

	
 
class new_email_requested(Email):
 
    """
 
    Sent when a new email address is requested for a customer,
 
    e.g. when entering a new customer order.
 
    """
 
    default_subject = "Email Update Request"
 

	
 
    def sample_data(self, request):
 
        model = request.rattail_config.get_model()
 
        customer = model.Customer(name="Fred Flintstone")
 
        return {
 
            'user': request.user,
 
            'user_display': request.user.display_name,
 
            'contact': customer,
 
            'contact_id': '42',
 
            'email_address': "fred@mailinator.com",
 
        }
 

	
 

	
 
class new_phone_requested(Email):
 
    """
 
    Sent when a new phone number is requested for a customer,
 
    e.g. when entering a new customer order.
 
    """
 
    default_subject = "Phone Update Request"
 

	
 
    def sample_data(self, request):
 
        model = request.rattail_config.get_model()
 
        customer = model.Customer(name="Fred Flintstone")
 
        return {
 
            'user': request.user,
 
            'user_display': request.user.display_name,
 
            'contact': customer,
 
            'contact_id': '42',
 
            'phone_number': "417-555-1234",
 
        }
 

	
 

	
 
class ImporterEmail(Email):
 
    """
 
    Sent when a "version catch-up" import is performed, which involves changes.
 
    """
 
    abstract = True
 
    fallback_key = 'rattail_import_updates'
rattail/templates/mail/new_email_requested.html.mako
Show inline comments
 
new file 100644
 
## -*- coding: utf-8; -*-
 
<html>
 
  <body>
 
    <h2>Contact Email Update Requested</h2>
 

	
 
    <p>
 
      A request to update a contact's email address was submitted by
 
      ${user_display}.
 
    </p>
 

	
 
    <ul>
 
      <li>
 
        Contact:&nbsp; ${contact_id} ${contact}
 
      </li>
 
      <li>
 
        New Email Address:&nbsp; ${email address}
 
      </li>
 
    </ul>
 

	
 
  </body>
 
</html>
rattail/templates/mail/new_phone_requested.html.mako
Show inline comments
 
new file 100644
 
## -*- coding: utf-8; -*-
 
<html>
 
  <body>
 
    <h2>Contact Phone Update Requested</h2>
 

	
 
    <p>
 
      A request to update a contact's phone number was submitted by
 
      ${user_display}.
 
    </p>
 

	
 
    <ul>
 
      <li>
 
        Contact:&nbsp; ${contact_id} ${contact}
 
      </li>
 
      <li>
 
        New Phone Number:&nbsp; ${phone_number}
 
      </li>
 
    </ul>
 

	
 
  </body>
 
</html>
0 comments (0 inline, 0 general)