diff --git a/rattail/batch/custorder.py b/rattail/batch/custorder.py index ffa82b4545a289910296f055295710c700e47f36..db24d9d993a0695deb5a400cfdb88de230418ace 100644 --- a/rattail/batch/custorder.py +++ b/rattail/batch/custorder.py @@ -126,20 +126,40 @@ class CustomerOrderBatchHandler(BatchHandler): 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): """ @@ -147,15 +167,10 @@ class CustomerOrderBatchHandler(BatchHandler): 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] @@ -181,15 +196,10 @@ class CustomerOrderBatchHandler(BatchHandler): 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 @@ -218,17 +228,12 @@ class CustomerOrderBatchHandler(BatchHandler): 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 - if email.invalid] + 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.") @@ -243,6 +248,10 @@ class CustomerOrderBatchHandler(BatchHandler): 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) @@ -464,8 +473,59 @@ class CustomerOrderBatchHandler(BatchHandler): 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', diff --git a/rattail/db/model/batch/core.py b/rattail/db/model/batch/core.py index 78fe0dabcf9eba7a2c41c882dd3866e692c7eb82..83d89a2230c84f617ce2a5004670b769b597468b 100644 --- a/rattail/db/model/batch/core.py +++ b/rattail/db/model/batch/core.py @@ -198,6 +198,24 @@ class BatchMixin(object): 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): """ diff --git a/rattail/emails.py b/rattail/emails.py index 3ac01121e014658a8ad64424c3eb04d0c4b2c69d..a4ab194348b0ad56cac1032a45d9ef3e1c7e789c 100644 --- a/rattail/emails.py +++ b/rattail/emails.py @@ -146,6 +146,44 @@ class filemon_action_error(Email): } +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. diff --git a/rattail/templates/mail/new_email_requested.html.mako b/rattail/templates/mail/new_email_requested.html.mako new file mode 100644 index 0000000000000000000000000000000000000000..27fde7a05d35785664e20212210d0a433f3107f7 --- /dev/null +++ b/rattail/templates/mail/new_email_requested.html.mako @@ -0,0 +1,21 @@ +## -*- coding: utf-8; -*- + +
++ A request to update a contact's email address was submitted by + ${user_display}. +
+ ++ A request to update a contact's phone number was submitted by + ${user_display}. +
+ +