Add support for Rattail -> CORE export/sync for Member data

also refactor CORE -> Rattail logic to use `api.set_member()` etc.
This commit is contained in:
Lance Edgar 2020-03-17 16:29:35 -05:00
parent 8d47a1449c
commit cb63644c7d
6 changed files with 326 additions and 79 deletions

View file

@ -31,14 +31,14 @@ from sqlalchemy import orm
from sqlalchemy.orm.exc import NoResultFound
from corepos.api import CoreWebAPI
from corepos.db.office_op import Session as CoreSession, model as corepos
from rattail import importing
from rattail.db import model
from rattail.gpc import GPC
from rattail.util import OrderedDict
from rattail.db.util import normalize_full_name, short_session
from rattail.db.util import normalize_full_name
from rattail_corepos import importing as corepos_importing
from rattail_corepos.corepos.util import get_core_members
log = logging.getLogger(__name__)
@ -75,32 +75,8 @@ class FromCOREPOSAPI(importing.Importer):
url = self.config.require('corepos.api', 'url')
self.api = CoreWebAPI(url)
def get_core_customers(self):
# TODO: ideally could do this, but API doesn't let us fetch "all"
# return self.api.get_customers()
# first we fetch all customer records from CORE DB
with short_session(Session=CoreSession) as s:
db_customers = s.query(corepos.Customer).all()
s.expunge_all()
# now we must fetch each customer account individually from API
customers = OrderedDict()
def fetch(dbcust, i):
if dbcust.card_number in customers:
return # already fetched this one
customer = self.api.get_customer(dbcust.card_number)
if customer:
customers[dbcust.card_number] = customer
else:
logger = log.warning if dbcust.account_holder else log.debug
logger("could not fetch customer from CORE API: %s",
dbcust.card_number)
self.progress_loop(fetch, db_customers,
message="Fetching Customer data from CORE API")
return list(customers.values())
def get_core_members(self):
return get_core_members(self.api, progress=self.progress)
class CustomerImporter(FromCOREPOSAPI, importing.model.CustomerImporter):
@ -115,26 +91,26 @@ class CustomerImporter(FromCOREPOSAPI, importing.model.CustomerImporter):
]
def get_host_objects(self):
return self.get_core_customers()
return self.get_core_members()
def normalize_host_object(self, customer):
def normalize_host_object(self, member):
# figure out the "account holder" person for the customer
people = customer['customers']
account_holders = [person for person in people
if person['accountHolder']]
# figure out the "account holder" customer for the member
customers = member['customers']
account_holders = [customer for customer in customers
if customer['accountHolder']]
if len(account_holders) > 1:
log.warning("customer %s has %s account holders in CORE: %s",
customer['cardNo'], len(account_holders), customer)
log.warning("member %s has %s account holders in CORE: %s",
member['cardNo'], len(account_holders), member)
elif not account_holders:
raise NotImplementedError("TODO: how to handle customer with no account holders?")
person = account_holders[0]
raise NotImplementedError("TODO: how to handle member with no account holders?")
customer = account_holders[0]
return {
'id': customer['customerAccountID'],
'number': customer['cardNo'],
'name': normalize_full_name(person['firstName'],
person['lastName']),
'id': member['customerAccountID'],
'number': member['cardNo'],
'name': normalize_full_name(customer['firstName'],
customer['lastName']),
}
@ -160,36 +136,36 @@ class PersonImporter(FromCOREPOSAPI, corepos_importing.model.PersonImporter):
def get_host_objects(self):
# first get all customer data from CORE API
customers = self.get_core_customers()
# first get all member data from CORE API
members = self.get_core_members()
normalized = []
# then collect all the "person" records
def normalize(customer, i):
normalized.extend(self.get_person_objects_for_customer(customer))
def normalize(member, i):
normalized.extend(self.get_person_objects_for_member(member))
self.progress_loop(normalize, customers,
self.progress_loop(normalize, members,
message="Collecting Person data from CORE")
return normalized
def get_person_objects_for_customer(self, customer):
def get_person_objects_for_member(self, member):
"""
Return a list of Person data objects for the given Customer. This
Return a list of Person data objects for the given Member. This
logic is split out separately so that datasync can leverage it too.
"""
records = []
people = []
# make sure we put the account holder first in the list!
people = sorted(customer['customers'],
key=lambda cust: 1 if cust['accountHolder'] else 0,
reverse=True)
customers = sorted(member['customers'],
key=lambda cust: 1 if cust['accountHolder'] else 0,
reverse=True)
for i, person in enumerate(people, 1):
person = dict(person)
for i, customer in enumerate(customers, 1):
person = dict(customer)
person['customer_person_ordinal'] = i
records.append(person)
people.append(person)
return records
return people
def get_customer(self, id):
if hasattr(self, 'customers'):
@ -250,24 +226,24 @@ class CustomerPersonImporter(FromCOREPOSAPI, importing.model.CustomerPersonImpor
def get_host_objects(self):
# first get all customer data from CORE API
customers = self.get_core_customers()
# first get all member data from CORE API
members = self.get_core_members()
normalized = []
# then collect all customer/person combination records
def normalize(customer, i):
def normalize(member, i):
# make sure we put the account holder first in the list!
people = sorted(customer['customers'],
key=lambda cust: 1 if cust['accountHolder'] else 0,
reverse=True)
for i, person in enumerate(people, 1):
customers = sorted(member['customers'],
key=lambda cust: 1 if cust['accountHolder'] else 0,
reverse=True)
for i, customer in enumerate(customers, 1):
normalized.append({
'customer_account_id': customer['customerAccountID'],
'person_customer_id': person['customerID'],
'customer_account_id': member['customerAccountID'],
'person_customer_id': customer['customerID'],
'ordinal': i,
})
self.progress_loop(normalize, customers,
self.progress_loop(normalize, members,
message="Collecting CustomerPerson data from CORE")
return normalized