From 36b8afb03b8ffba06b5cf762787f9306ef3e6ab5 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sun, 15 Mar 2020 19:29:47 -0500 Subject: [PATCH] Add support for Customer data in CORE API -> Rattail import/sync --- rattail_corepos/datasync/rattail.py | 2 + rattail_corepos/importing/corepos/api.py | 66 ++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/rattail_corepos/datasync/rattail.py b/rattail_corepos/datasync/rattail.py index a87573f..867397c 100644 --- a/rattail_corepos/datasync/rattail.py +++ b/rattail_corepos/datasync/rattail.py @@ -47,6 +47,8 @@ class FromCOREAPIToRattail(NewDataSyncImportConsumer): self.api = CoreWebAPI(url) def get_host_object(self, session, change): + if change.payload_type == 'Customer': + return self.api.get_customer(change.payload_key) if change.payload_type == 'Department': return self.api.get_department(change.payload_key) if change.payload_type == 'Subdepartment': diff --git a/rattail_corepos/importing/corepos/api.py b/rattail_corepos/importing/corepos/api.py index 5a63d86..29e1ec7 100644 --- a/rattail_corepos/importing/corepos/api.py +++ b/rattail_corepos/importing/corepos/api.py @@ -28,10 +28,12 @@ import decimal import logging from corepos.api import CoreWebAPI +from corepos.db.office_op import Session as CoreSession, model as corepos from rattail import importing from rattail.gpc import GPC from rattail.util import OrderedDict +from rattail.db.util import normalize_full_name, short_session from rattail_corepos import importing as corepos_importing @@ -46,6 +48,7 @@ class FromCOREPOSToRattail(importing.ToRattailHandler): def get_importers(self): importers = OrderedDict() + importers['Customer'] = CustomerImporter importers['Department'] = DepartmentImporter importers['Subdepartment'] = SubdepartmentImporter importers['Vendor'] = VendorImporter @@ -67,6 +70,69 @@ class FromCOREPOSAPI(importing.Importer): self.api = CoreWebAPI(url) +class CustomerImporter(FromCOREPOSAPI, importing.model.CustomerImporter): + """ + Importer for customer data from CORE POS API. + """ + key = 'number' + supported_fields = [ + 'id', + 'number', + 'name', + 'first_name', + 'last_name', + ] + + def get_host_objects(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.person_number == 1 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-POS API") + return list(customers.values()) + + def normalize_host_object(self, customer): + + # figure out the "account holder" person for the customer + people = customer['customers'] + account_holders = [person for person in people + if person['accountHolder']] + if len(account_holders) > 1: + log.warning("customer %s has %s account holders in CORE: %s", + customer['cardNo'], len(account_holders), customer) + elif not account_holders: + raise NotImplementedError("TODO: how to handle customer with no account holders?") + person = account_holders[0] + + return { + 'id': customer['customerAccountID'], + 'number': int(customer['cardNo']), + 'name': normalize_full_name(person['firstName'], + person['lastName']), + 'first_name': person['firstName'], + 'last_name': person['lastName'], + } + + class DepartmentImporter(FromCOREPOSAPI, importing.model.DepartmentImporter): """ Importer for department data from CORE POS API.