diff --git a/inflatinator/revbank.py b/inflatinator/revbank.py index 0c4bd4e..0e88a8a 100644 --- a/inflatinator/revbank.py +++ b/inflatinator/revbank.py @@ -5,7 +5,14 @@ import logging import scrapers import shlex -profit_margin = Decimal('1.3') + +def resale_price(prod: scrapers.Product) -> Decimal: + profit_margin = Decimal('1.3') + + # Apply profit margin and divide by the number of units per sold packaging. + unit_price = prod.price * profit_margin / prod.units + # Round up to 5ct. + return (unit_price * 20).quantize(Decimal('1'), rounding=ROUND_UP) / 20 @dataclass @@ -42,6 +49,15 @@ class Product: metadata=metadata, ) + @staticmethod + def from_scraper(prod: scrapers.Product): + return Product( + aliases=[prod.gtin, *sorted(prod.aliases)], + price=resale_price(prod), + description=prod.name, + metadata={}, + ) + def format_line(self): aliases = ','.join(self.aliases) price = f'{self.price:.2f}' @@ -83,36 +99,60 @@ def update_product_pricings(src): try: prod_info = find_product_details(product) + except NoAutoUpdate: logging.debug('no auto update: "%s"', product.description) lines_out.append(line) continue + except scrapers.ProductNotFoundError: - logging.warn('not found "%s"', product.description) product.metadata['err'] = 'not_found' + # If this product was not found and has a substitute reference in its metadata, clear the scraping trigger. + if 'sub' in product.metadata and 'sligro' in product.metadata: + del product.metadata['sligro'] + logging.info('"%s" is EOL', product.description) + else: + logging.warn('not found "%s"', product.description) lines_out.append(product.format_line()) continue + except Exception as err: logging.error('did not update "%s": %s', product.description, err) lines_out.append(line) continue - aliases = sorted(set(product.aliases) - {prod_info.gtin}) - product.aliases = [prod_info.gtin, *aliases] + new_product = Product.from_scraper(prod_info) - # Apply profit margin and divide by the number of units per sold packaging. - unit_price = prod_info.price * profit_margin / prod_info.units - # Round up to 5ct. + product.description = new_product.description + logging.debug(f'Found "{new_product.description}", buy €{prod_info.price/prod_info.units:.2f}, sell €{new_product.price:.2f}') + + # Merge any new aliases, keeping the gtin first. + product.aliases = [ + prod_info.gtin, + *sorted((set(product.aliases) | set(new_product.aliases)) - {prod_info.gtin}) + ] + # Adjust the price. previous_price = product.price - product.price = (unit_price * 20).quantize(Decimal('1'), rounding=ROUND_UP) / 20 - + product.price = new_product.price + if product.price != previous_price: + logging.info(f'Adjusted "{product.description}", €{previous_price:.2f} -> €{product.price:.2f}') + # If this product had an error set for any reason, clear it. if 'err' in product.metadata: del product.metadata['err'] + # If this product is being substituted by another product, leave a reference. + # This will also help us determine whether the substitute has been rewritten already. + substitute_product = None + if prod_info.replacement is not None: + if 'sub' not in product.metadata: + substitute_product = Product.from_scraper(prod_info.replacement) + substitute_product.metadata['sligro'] = None + product.metadata['sub'] = prod_info.replacement.gtin + lines_out.append(product.format_line()) - logging.debug(f'Found "{prod_info.name}", buy €{prod_info.price/prod_info.units:.2f}, sell €{product.price:.2f}') - if product.price != previous_price: - logging.info(f'Adjusted "{prod_info.name}", €{previous_price:.2f} -> €{product.price:.2f}') + if substitute_product is not None: + lines_out.append(substitute_product.format_line()) + logging.info(f'Found replacement of "{product.description}": {substitute_product.aliases[0]}') return '\n'.join(lines_out)