From ff01525aa7ae8dcd506ffeea68d1ba135312bdef 2023-05-18 23:23:56 From: Lance Edgar Date: 2023-05-18 23:23:56 Subject: [PATCH] Add `get_person()`, `get_customer()` etc. to AppHandler make it delegate to appropriate handler for each method. also the various handler methods with actual logic, are a bit more generic in what they accept --- diff --git a/rattail/app.py b/rattail/app.py index a1dfb573d8b3b94a08d4f754ecbdc09069378040..b7873d322b26f82468349e661c9b03700da21482 100644 --- a/rattail/app.py +++ b/rattail/app.py @@ -1157,6 +1157,42 @@ class AppHandler(object): """ return Object(**kwargs) + def get_person(self, obj, **kwargs): + """ + Convenience method to locate a Person record for the given + object. This delegates to the + :class:`~rattail.people.PeopleHandler` for actual lookup + logic. + """ + return self.get_people_handler().get_person(obj, **kwargs) + + def get_customer(self, obj, **kwargs): + """ + Convenience method to locate a Customer record for the given + object. This delegates to the + :class:`~rattail.clientele.ClienteleHandler` for actual lookup + logic. + """ + return self.get_clientele_handler().get_customer(obj, **kwargs) + + def get_employee(self, obj, **kwargs): + """ + Convenience method to locate an Employee record for the given + object. This delegates to the + :class:`~rattail.employment.EmploymentHandler` for actual + lookup logic. + """ + return self.get_employment_handler().get_employee(obj, **kwargs) + + def get_member(self, obj, **kwargs): + """ + Convenience method to locate a Member record for the given + object. This delegates to the + :class:`~rattail.membershipo.MembershipHandler` for actual + lookup logic. + """ + return self.get_membership_handler().get_member(obj, **kwargs) + def get_session(self, obj): """ Returns the SQLAlchemy session with which the given object is diff --git a/rattail/batch/custorder.py b/rattail/batch/custorder.py index 643593cb7a7d5d0bf94d82d3d3acc6f08434b074..45bd4ecdf552f84487af9c73147e9b4be1609e40 100644 --- a/rattail/batch/custorder.py +++ b/rattail/batch/custorder.py @@ -174,7 +174,7 @@ class CustomerOrderBatchHandler(BatchHandler): # nb. person is always required if customer and not person: - person = clientele.get_person(customer) + person = self.app.get_person(customer) if not person: raise ValueError("Must specify a person") diff --git a/rattail/clientele.py b/rattail/clientele.py index d2946b506db8d71a32334d646f1b720831bceb52..698c41944924e28646b057ae0e765ecacf987f0e 100644 --- a/rattail/clientele.py +++ b/rattail/clientele.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2022 Lance Edgar +# Copyright © 2010-2023 Lance Edgar # # This file is part of Rattail. # @@ -24,7 +24,7 @@ Clientele Handler """ -from __future__ import unicode_literals, absolute_import +import warnings from rattail.util import load_object from rattail.app import GenericHandler @@ -65,17 +65,28 @@ class ClienteleHandler(GenericHandler): session.refresh(person) return customer - def get_customer(self, person): + def get_customer(self, obj): """ - Returns the customer associated with the given person, if there is one. + Return the Customer associated with the given object, if any. """ - return person.only_customer(require=False) + model = self.model + + if isinstance(obj, model.Customer): + return obj + + if isinstance(obj, model.Person): + customer = person.only_customer(require=False) + if customer: + return customer def get_person(self, customer): """ Returns the person associated with the given customer, if there is one. """ - return customer.only_person(require=False) + warnings.warn("ClienteleHandler.get_person() is deprecated; " + "please use AppHandler.get_person() instead") + + return self.app.get_person(member) def make_customer(self, person, **kwargs): """ @@ -95,7 +106,7 @@ class ClienteleHandler(GenericHandler): if phone: return phone - person = self.get_person(customer) + person = self.app.get_person(customer) if person: return person.first_phone() @@ -117,7 +128,7 @@ class ClienteleHandler(GenericHandler): if email: return email - person = self.get_person(customer) + person = self.app.get_person(customer) if person: return person.first_email(invalid=invalid) diff --git a/rattail/employment.py b/rattail/employment.py index 11381cbc16b880182430cded8e5911cad7c907a5..9bdfadad9f207e8c533239b6b24c8fec2e351fb5 100644 --- a/rattail/employment.py +++ b/rattail/employment.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2022 Lance Edgar +# Copyright © 2010-2023 Lance Edgar # # This file is part of Rattail. # @@ -24,10 +24,6 @@ Employment Handler """ -from __future__ import unicode_literals, absolute_import - -import six - from rattail.util import load_object from rattail.app import GenericHandler @@ -106,11 +102,19 @@ class EmploymentHandler(GenericHandler): session.flush() return employee - def get_employee(self, person): + def get_employee(self, obj): """ - Returns the employee associated with the given person, if there is one. + Returns the Employee associated with the given object, if any. """ - return person.employee + model = self.model + + if isinstance(obj, model.Employee): + return obj + + if isinstance(obj, model.Person): + emplyoyee = person.employee + if employee: + return employee def make_employee(self, person): """ @@ -167,8 +171,8 @@ class EmploymentHandler(GenericHandler): 'status': employee.status, 'status_display': status_display, 'current': employee.status == self.enum.EMPLOYEE_STATUS_CURRENT, - 'start_date': six.text_type(history.start_date) if history else None, - 'end_date': six.text_type(history.end_date) if history and history.end_date else None, + 'start_date': str(history.start_date) if history else None, + 'end_date': str(history.end_date) if history and history.end_date else None, } diff --git a/rattail/membership.py b/rattail/membership.py index f8d04f5b6d0b08a23085f4d7b8c4b39ddf7bd37d..1a2db059366c9f5a0369aa1f1cc4d641ab456c63 100644 --- a/rattail/membership.py +++ b/rattail/membership.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2022 Lance Edgar +# Copyright © 2010-2023 Lance Edgar # # This file is part of Rattail. # @@ -24,7 +24,7 @@ Membership Handler """ -from __future__ import unicode_literals, absolute_import +import warnings from rattail.util import load_object from rattail.app import GenericHandler @@ -54,11 +54,18 @@ class MembershipHandler(GenericHandler): """ raise NotImplementedError - def get_member(self, person): + def get_member(self, obj): """ Returns the member associated with the given person, if there is one. """ - raise NotImplementedError + model = self.model + + if isinstance(obj, model.Member): + return obj + + person = self.app.get_person(obj) + if person and person.members: + return person.members[0] def get_customer(self, member): """ @@ -70,10 +77,10 @@ class MembershipHandler(GenericHandler): """ Returns the person associated with the given member, if there is one. """ - clientele = self.app.get_clientele_handler() - customer = self.get_customer(member) - person = clientele.get_person(customer) - return person + warnings.warn("MembershipHandler.get_person() is deprecated; " + "please use AppHandler.get_person() instead") + + return self.app.get_person(member) def get_last_patronage_date(self, member, **kwargs): raise NotImplementedError diff --git a/rattail/people.py b/rattail/people.py index 39e14995ce888328fd82d2ba89b7e08e06dc36cd..0116e5b557c8753fa4c188676040e29f2f812602 100644 --- a/rattail/people.py +++ b/rattail/people.py @@ -39,6 +39,37 @@ class PeopleHandler(GenericHandler, MergeMixin): Base class and default implementation for people handlers. """ + def get_person(self, obj, **kwargs): + """ + Retrieve the Person related to the given object. + + This is a rather fundamental method, in that it is called by + several other methods, both within this handler as well as + others. There is even a shortcut to it, accessible via + :meth:`rattail.app.AppHandler.get_person()`. + + Its purpose is to navigate relationships as needed, to get at + the "default" person associated with the object. Depending on + how the app tracks relationships, this logic may need to vary. + """ + model = self.model + + if isinstance(obj, model.Person): + return obj + + if isinstance(obj, model.User): + if obj.person: + return obj.person + + if isinstance(obj, model.Customer): + person = obj.only_person(require=False) + if person: + return person + + if isinstance(obj, model.Member): + if obj.person: + return obj.person + def normalize_full_name(self, first, last, **kwargs): """ Normalize a "full" name based on the given first and last