Add 2-way sync for basic Member data, CORE <-> Rattail
This commit is contained in:
parent
9dbdb81f07
commit
8917316a21
5 changed files with 158 additions and 14 deletions
|
@ -24,6 +24,7 @@
|
|||
CORE POS (API) -> Rattail data importing
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import decimal
|
||||
import logging
|
||||
|
||||
|
@ -55,6 +56,7 @@ class FromCOREPOSToRattail(importing.ToRattailHandler):
|
|||
importers['Customer'] = CustomerImporter
|
||||
importers['Person'] = PersonImporter
|
||||
importers['CustomerPerson'] = CustomerPersonImporter
|
||||
importers['Member'] = MemberImporter
|
||||
importers['Department'] = DepartmentImporter
|
||||
importers['Subdepartment'] = SubdepartmentImporter
|
||||
importers['Vendor'] = VendorImporter
|
||||
|
@ -100,20 +102,32 @@ class CustomerImporter(FromCOREPOSAPI, importing.model.CustomerImporter):
|
|||
|
||||
def normalize_host_object(self, member):
|
||||
|
||||
# figure out the "account holder" customer for the member
|
||||
if member['customerAccountID'] == 0:
|
||||
log.debug("member %s has customerAccountID of 0: %s",
|
||||
member['cardNo'], member)
|
||||
return
|
||||
|
||||
# figure out the "account holder" customer for the member. note that
|
||||
# we only use this to determine the `Customer.name` in Rattail
|
||||
customers = member['customers']
|
||||
account_holders = [customer for customer in customers
|
||||
if customer['accountHolder']]
|
||||
if len(account_holders) > 1:
|
||||
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 member with no account holders?")
|
||||
customer = account_holders[0]
|
||||
if account_holders:
|
||||
if len(account_holders) > 1:
|
||||
log.warning("member %s has %s account holders in CORE: %s",
|
||||
member['cardNo'], len(account_holders), member)
|
||||
customer = account_holders[0]
|
||||
elif customers:
|
||||
if len(customers) > 1:
|
||||
log.warning("member %s has %s customers but no account holders: %s",
|
||||
member['cardNo'], len(customers), member)
|
||||
customer = customers[0]
|
||||
else:
|
||||
raise NotImplementedError("TODO: how to handle member with no customers?")
|
||||
|
||||
return {
|
||||
'id': member['customerAccountID'],
|
||||
'number': member['cardNo'],
|
||||
'number': int(member['cardNo']),
|
||||
'name': normalize_full_name(customer['firstName'],
|
||||
customer['lastName']),
|
||||
|
||||
|
@ -167,12 +181,22 @@ class PersonImporter(FromCOREPOSAPI, corepos_importing.model.PersonImporter):
|
|||
Return a list of Person data objects for the given Member. This
|
||||
logic is split out separately so that datasync can leverage it too.
|
||||
"""
|
||||
customers = member['customers']
|
||||
people = []
|
||||
|
||||
# make sure we put the account holder first in the list!
|
||||
customers = sorted(member['customers'],
|
||||
key=lambda cust: 1 if cust['accountHolder'] else 0,
|
||||
reverse=True)
|
||||
# make sure account holder is listed first
|
||||
account_holder = None
|
||||
secondary = False
|
||||
mixedup = False
|
||||
for customer in customers:
|
||||
if customer['accountHolder'] and not secondary:
|
||||
account_holder = customer
|
||||
elif not customer['accountHolder']:
|
||||
secondary = True
|
||||
elif customer['accountHolder'] and secondary:
|
||||
mixedup = True
|
||||
if mixedup:
|
||||
raise NotImplementedError("TODO: should re-sort the customers list for member {}".format(member['cardNo']))
|
||||
|
||||
for i, customer in enumerate(customers, 1):
|
||||
person = dict(customer)
|
||||
|
@ -450,3 +474,81 @@ class ProductImporter(FromCOREPOSAPI, importing.model.ProductImporter):
|
|||
'regular_price_multiple': 1 if price is not None else None,
|
||||
'regular_price_type': self.enum.PRICE_TYPE_REGULAR if price is not None else None,
|
||||
}
|
||||
|
||||
|
||||
class MemberImporter(FromCOREPOSAPI, importing.model.MemberImporter):
|
||||
"""
|
||||
Importer for member data from CORE POS API.
|
||||
"""
|
||||
key = 'id'
|
||||
supported_fields = [
|
||||
'id',
|
||||
'customer_uuid',
|
||||
'joined',
|
||||
'withdrew',
|
||||
]
|
||||
|
||||
# TODO: should make this configurable
|
||||
member_status_codes = [
|
||||
'PC',
|
||||
'TERM',
|
||||
]
|
||||
|
||||
# TODO: should make this configurable
|
||||
non_member_status_codes = [
|
||||
'REG',
|
||||
'INACT',
|
||||
]
|
||||
|
||||
def setup(self):
|
||||
super(MemberImporter, self).setup()
|
||||
self.customers = self.cache_model(model.Customer, key='number')
|
||||
|
||||
def get_host_objects(self):
|
||||
return self.get_core_members()
|
||||
|
||||
def get_customer(self, number):
|
||||
if hasattr(self, 'customers'):
|
||||
return self.customers.get(number)
|
||||
|
||||
try:
|
||||
return self.session.query(model.Customer)\
|
||||
.filter(model.Customer.number == number)\
|
||||
.one()
|
||||
except NoResultFound:
|
||||
pass
|
||||
|
||||
def normalize_host_object(self, member):
|
||||
customer = self.get_customer(member['cardNo'])
|
||||
if not customer:
|
||||
log.warning("Rattail customer not found for cardNo %s: %s",
|
||||
member['cardNo'], member)
|
||||
return
|
||||
|
||||
if member['memberStatus'] in self.non_member_status_codes:
|
||||
log.debug("skipping non-member %s with status '%s': %s",
|
||||
member['memberStatus'], member['cardNo'], member)
|
||||
return
|
||||
if member['memberStatus'] not in self.member_status_codes:
|
||||
# note that we will still import this one! we don't skip it
|
||||
log.warning("unexpected status '%s' for member %s: %s",
|
||||
member['memberStatus'], member['cardNo'], member)
|
||||
|
||||
joined = None
|
||||
if member['startDate'] and member['startDate'] != '0000-00-00 00:00:00':
|
||||
joined = datetime.datetime.strptime(member['startDate'],
|
||||
'%Y-%m-%d %H:%M:%S')
|
||||
joined = joined.date()
|
||||
|
||||
withdrew = None
|
||||
if member['endDate'] and member['endDate'] != '0000-00-00 00:00:00':
|
||||
withdrew = datetime.datetime.strptime(member['endDate'],
|
||||
'%Y-%m-%d %H:%M:%S')
|
||||
withdrew = withdrew.date()
|
||||
|
||||
return {
|
||||
'id': str(member['cardNo']),
|
||||
'customer_uuid': customer.uuid,
|
||||
'joined': joined,
|
||||
'withdrew': withdrew,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue