fix: improve ProductCost sorting for import from CORE API

this hopefully ensures a more consistent preference order, fewer diffs
This commit is contained in:
Lance Edgar 2024-07-02 22:44:55 -05:00
parent eb9a1ae4f0
commit 2f22be6e7e

View file

@ -655,9 +655,7 @@ class ProductCostImporter(FromCOREPOSAPI, corepos_importing.model.ProductCostImp
""" """
Importer for product cost data from CORE POS API. Importer for product cost data from CORE POS API.
""" """
# TODO: should change key after live sites are updated key = ('corepos_vendor_id', 'corepos_sku')
key = ('vendor_uuid', 'code')
# key = ('corepos_vendor_id', 'corepos_sku')
supported_fields = [ supported_fields = [
'corepos_vendor_id', 'corepos_vendor_id',
'corepos_sku', 'corepos_sku',
@ -696,7 +694,63 @@ class ProductCostImporter(FromCOREPOSAPI, corepos_importing.model.ProductCostImp
key='item_id') key='item_id')
def get_host_objects(self): def get_host_objects(self):
return self.api.get_vendor_items()
# first we will cache API products by upc
products = OrderedDict()
def cache(product, i):
if product.get('upc'):
products[product['upc']] = product
self.progress_loop(cache, self.api.get_products(),
message="Caching product data from CORE")
# next we cache API vendor items, also by upc
vendor_items = {}
def cache(item, i):
if not item['upc']:
log.warning("CORE vendor item has no upc: %s", item)
return
if item['vendorID'] == '0':
log.warning("CORE vendor item has no vendorID: %s", item)
return
vendor_items.setdefault(item['upc'], []).append(item)
self.progress_loop(cache, self.api.get_vendor_items(),
message="Caching vendor item data from CORE")
# now we must "sort" the vendor items for each upc. to do
# this we just ensure the item for default vendor is first
def organize(upc, i):
product = products.get(upc)
if not product:
return # product not found
vendor_id = product['default_vendor_id']
if not vendor_id:
return # product has no default vendor
items = vendor_items[upc]
for item in items:
if item['vendorID'] == vendor_id:
# found the default vendor item
j = items.index(item)
if j != 0:
# it was not first; make it so
items.pop(j)
items.insert(0, item)
break
self.progress_loop(organize, list(vendor_items),
message="Sorting items by default vendor")
# keep the vendor item cache for reference later
self.api_vendor_items = vendor_items
# host objects are the API products (in original sequence)
return list(products.values())
def get_vendor(self, item): def get_vendor(self, item):
corepos_id = int(item['vendorID']) corepos_id = int(item['vendorID'])
@ -733,6 +787,31 @@ class ProductCostImporter(FromCOREPOSAPI, corepos_importing.model.ProductCostImp
except orm.exc.NoResultFound: except orm.exc.NoResultFound:
pass pass
def normalize_host_data(self, host_objects=None):
# TODO: this all seems a bit hacky but works for now..
# could even be we don't need this method?
if host_objects is None:
host_objects = self.get_host_objects()
normalized = []
self.sorted_vendor_items = {}
def normalize(product, i):
if not product.get('upc'):
log.warning("product has no upc: %s", product)
return
items = self.sort_vendor_items(product)
self.sorted_vendor_items[product['upc']] = items
for item in items:
data = self.normalize_host_object(item)
if data:
normalized.append(data)
self.progress_loop(normalize, host_objects,
message=f"Reading Product data from {self.host_system_title}")
return normalized
def normalize_host_object(self, item): def normalize_host_object(self, item):
vendor = self.get_vendor(item) vendor = self.get_vendor(item)
if not vendor: if not vendor:
@ -752,10 +831,6 @@ class ProductCostImporter(FromCOREPOSAPI, corepos_importing.model.ProductCostImp
# log.warning("CORE POS product not found for item: %s", item) # log.warning("CORE POS product not found for item: %s", item)
# return # return
preferred = False
if core_product and core_product['default_vendor_id'] == item['vendorID']:
preferred = True
case_size = decimal.Decimal(item['units']) case_size = decimal.Decimal(item['units'])
unit_cost = item.get('cost') unit_cost = item.get('cost')
if unit_cost is not None: if unit_cost is not None:
@ -764,7 +839,7 @@ class ProductCostImporter(FromCOREPOSAPI, corepos_importing.model.ProductCostImp
if unit_cost is not None: if unit_cost is not None:
case_cost = unit_cost * case_size case_cost = unit_cost * case_size
return { data = {
'corepos_vendor_id': int(item['vendorID']), 'corepos_vendor_id': int(item['vendorID']),
'corepos_sku': item['sku'], 'corepos_sku': item['sku'],
'product_uuid': product.uuid, 'product_uuid': product.uuid,
@ -773,9 +848,35 @@ class ProductCostImporter(FromCOREPOSAPI, corepos_importing.model.ProductCostImp
'case_size': case_size, 'case_size': case_size,
'case_cost': case_cost, 'case_cost': case_cost,
'unit_cost': unit_cost, 'unit_cost': unit_cost,
'preferred': preferred,
} }
if self.fields_active(['preference', 'preferred']):
items = self.get_sorted_vendor_items(item)
i = items.index(item)
data['preference'] = i + 1
data['preferred'] = i == 0
return data
def get_sorted_vendor_items(self, item):
if hasattr(self, 'sorted_vendor_items'):
return self.sorted_vendor_items.get(item['upc'])
product = self.api.get_product(item['upc'])
return self.sort_vendor_items(product)
def sort_vendor_items(self, product):
# TODO: this all seems a bit hacky but works for now..
if not product.get('upc'):
return []
if hasattr(self, 'api_vendor_items'):
return self.api_vendor_items.get(product['upc'], [])
raise NotImplementedError("must add real-time datasync support")
class MembershipTypeImporter(FromCOREPOSAPI, importing.model.MembershipTypeImporter): class MembershipTypeImporter(FromCOREPOSAPI, importing.model.MembershipTypeImporter):
""" """