aboutsummaryrefslogtreecommitdiff
path: root/src/ee/digikey
diff options
context:
space:
mode:
Diffstat (limited to 'src/ee/digikey')
-rw-r--r--src/ee/digikey/__init__.py59
-rw-r--r--src/ee/digikey/search_parts.py8
2 files changed, 60 insertions, 7 deletions
diff --git a/src/ee/digikey/__init__.py b/src/ee/digikey/__init__.py
index 6baae84..f67e6b5 100644
--- a/src/ee/digikey/__init__.py
+++ b/src/ee/digikey/__init__.py
@@ -13,32 +13,35 @@ from lxml import html
from selenium import webdriver
import ee._utils
+from ee.money import Money, get_default_context
from ee.tools import mk_parents
+money = get_default_context()
-def normalize_filename(part):
+
+def normalize_filename(part) -> str:
return part.replace('/', '_').replace(' ', '_')
-def _clean(s):
+def _clean(s) -> Optional[str]:
if s is None:
return None
s = s.strip()
return None if len(s) == 0 else s
-def _to_string(e):
+def _to_string(e) -> str:
s = ""
for t in e.itertext():
s += t
return s.strip()
-def _parse_int(s):
+def _parse_int(s) -> int:
return int(s.replace(',', '').replace('.', ''))
-def _to_int(s):
+def _to_int(s) -> Optional[int]:
try:
return _parse_int(s)
except ValueError:
@@ -69,16 +72,24 @@ class Digikey(object):
return a
+class PriceBreak(object):
+ def __init__(self, quantity: int, per_piece_price: Money, per_quantity_price: Money):
+ self.quantity = quantity
+ self.per_piece_price = per_piece_price
+ self.per_quantity_price = per_quantity_price
+
+
@total_ordering
class DigikeyProduct(object):
def __init__(self, part_number, mpn, url, attributes: List["DigikeyAttributeValue"] = None, categories=None):
self.part_number = _clean(part_number)
self.mpn = _clean(mpn)
self.url = url
- self.attributes = attributes or [] # type: List["DigikeyAttributeValue"]
+ self.attributes = attributes or [] # type: List["DigikeyAttributeValue"]
self.categories = categories or []
self.quantity_available = None
self.description = None
+ self.price_breaks: List[PriceBreak] = []
assert self.part_number
assert self.mpn
@@ -214,7 +225,7 @@ class DigikeyClient(object):
def __init__(self, cache_dir: Path = None, on_download=None):
self.on_download = on_download or self.__nop
self.cache = ee._utils.maybe_cache(cache_dir)
- self.driver: webdriver.Chrome = None
+ self.driver: Optional[webdriver.Chrome] = None
def search(self, query: str, page_size=10) -> str:
return self.product_search(query, page_size)
@@ -291,6 +302,7 @@ class DigikeyParser(object):
if part_number and mpn:
p = DigikeyProduct(part_number, mpn, url, attributes, categories)
+ p.price_breaks = self._parse_price_breaks(tree)
for n in tree.xpath("//*[@itemprop='description']"):
p.description = _to_string(n)
return p
@@ -298,6 +310,39 @@ class DigikeyParser(object):
return None
@staticmethod
+ def _find_currency(tree: html) -> Optional[str]:
+ for e in tree.xpath("//*[@id='cur-dropdown']"):
+ s = _clean(e.text)
+ if s:
+ return s
+
+ def _parse_price_breaks(self, tree: html) -> List[PriceBreak]:
+ currency = self._find_currency(tree)
+
+ price_breaks = []
+
+ ok = True
+ for row in tree.xpath("//table[@class='product-dollars']//tr"):
+ tds = list(row.xpath("./td"))
+
+ if len(tds) != 3:
+ continue
+
+ tds = ["".join(td.xpath("./descendant-or-self::*/text()")) for td in tds]
+
+ quantity = _to_int(tds[0])
+ price = money.try_parse(tds[1], currency=currency)
+
+ if quantity is None or price is None:
+ ok = False
+ break
+
+ price_breaks.append(PriceBreak(quantity=quantity, per_piece_price=price,
+ per_quantity_price=price * quantity))
+
+ return price_breaks if ok else []
+
+ @staticmethod
def _handle_product_table(tree: html, res: DigikeySearchResponse):
products = tree.xpath("//*[@itemtype='http://schema.org/Product']")
diff --git a/src/ee/digikey/search_parts.py b/src/ee/digikey/search_parts.py
index 9c8eb74..61c5c1b 100644
--- a/src/ee/digikey/search_parts.py
+++ b/src/ee/digikey/search_parts.py
@@ -27,6 +27,14 @@ def resolved(p: DigikeyProduct) -> bomFile.Part:
key = make_digikey_fact_key(a.attribute_type.id)
facts.append(bomFile.Fact(key=key, label=a.attribute_type.label, value=a.value))
+ if len(p.price_breaks):
+ part.price_breaksProp = bomFile.PriceBreakList()
+
+ price_breaks: List[bomFile.PriceBreak] = part.price_breaksProp.price_break
+ for pb in p.price_breaks:
+ amount = bomFile.Amount(value=str(pb.per_piece_price.amount), currency=pb.per_piece_price.currency)
+ price_breaks.append(bomFile.PriceBreak(pb.quantity, amount=amount))
+
return part