<file_sep># taxfree-searcher
Simple code to generate a database comparing airport tax-free and vinmonopolet using their respective APIs.


# Structure
- db_creator.py - create sqlite database to store values
- filedump.py - simple file to dump output to file
- main.py - file to search tax-free.no for goods, and lookup at vinmonopolet for corresponding prices
- taxfree.py - lookup taxfree products using the algoli api
- vinmonopolet.py - lookup for products using the vinmonopolet api


# Required keys
A app id and secret is needed for the algoli api with search priveliges.
An api key is needed for the vinmonopolet api with access to the "open" api.<file_sep>from algoliasearch.search_client import SearchClient


class TaxFree:

    def __init__(self):
        appid = ''
        apikey = ''

        self.client = SearchClient.create(appid, apikey)
        self.index = self.client.init_index('products')

    def search(self, search_string, category, sub_category=None, sub_sub_category=None):
        # Search without sub-category is a bad idea, as the max returned search items is 1k

        page = 0
        hits = []

        if sub_sub_category is not None:
            category_filter = 'categoryPathHierarchy.lvl1:"{} > {} > {}"'.format(category.capitalize(),
                                                                                 sub_category.capitalize(),
                                                                                 sub_sub_category.capitalize())
        elif sub_category is not None:
            category_filter = 'categoryPathHierarchy.lvl1:"{} > {}"'.format(category.capitalize(),
                                                                            sub_category.capitalize())
        else:
            category_filter = 'categoryPathHierarchy.lvl0:{}'.format(category.capitalize())

        while True:
            result = self.index.search(search_string,
                                       {
                                           'filters': category_filter,
                                           'hitsPerPage': 100,
                                           'page': page
                                       })
            hits.extend(result['hits'])
            total_pages = result['nbPages']
            page = result['page'] + 1

            if page > total_pages:
                return hits

    def browse(self, category):
        # Browse needs to be allowed by the api key
        search_category = category.capitalize()
        result = self.index.browse_objects(
            {
                'filters': 'categoryPathHierarchy.lvl0:{}'.format(search_category),
                'query': '',
            })
        return result


<file_sep>import sqlite3

db = sqlite3.connect('database')
cursor = db.cursor()
cursor.execute('''
    CREATE TABLE products(id INTEGER PRIMARY KEY, timestamp TEXT, barcode TEXT, category TEXT, sub_category TEXT, tf_name TEXT, vm_name TEXT,
                       tf_price REAL, vm_price REAL, diff_price REAL, perc_diff_price REAL)
''')
db.commit()
db.close()
<file_sep>import requests
import json


class Vinmonopolet:

    def __init__(self):
        self.apikey = ''
        self.headers = {'Ocp-Apim-Subscription-Key': self.apikey}

    def search(self, search_string):
        search_string = search_string.split(" ")[0]
        url = 'https://apis.vinmonopolet.no/products/v0/details-normal' \
              '?productShortNameContains={}'.format(search_string)
        response = requests.get(url=url, headers=self.headers)
        return json.loads(response.text)
<file_sep>from taxfree import TaxFree
import json

search = TaxFree()

for vine_type in ['rødvin', 'hvitvin', 'rosévin', 'ressertvin', 'musserende', 'sterkvin', 'perlende vin']:
    with open('{}.json'.format(vine_type), 'w') as outfile:
        json.dump(search.search('', 'vin', vine_type), outfile)

with open('beer.json', 'w') as outfile:
    beers = search.search('', 'øl')
    json.dump(beers, outfile)

with open('brennevin.json', 'w') as outfile:
    fortified = search.search('', 'brennevin')
    json.dump(fortified, outfile)
<file_sep>from taxfree import TaxFree
from vinmonopolet import Vinmonopolet
import sqlite3
import datetime


def get_vm_product_price(tf_name, tf_barcode):
    for vm_product in vm.search(tf_name):
        vm_name = vm_product['basic']['productLongName']
        vm_barcodes = vm_product['logistics']['barcodes']
        if len(vm_product['prices']) >= 1:
            vm_price = vm_product['prices'][0]['salesPrice']
        else:
            return None, None

        for vm_barcode in vm_barcodes:
            if vm_barcode['gtin'] == tf_barcode:
                return vm_name, vm_price
    return None, None


def lookup_and_store_search(tf_search_result, tf_search_category, tf_search_sub_category):
    for tf_product in tf_search_result:
        tf_name = tf_product['name']
        tf_barcode = tf_product['ean']
        tf_price = tf_product['price']['value']
        vm_name, vm_price = get_vm_product_price(tf_name, tf_barcode)

        if vm_price is not None:
            diff_price = vm_price - tf_price
            perc_diff_price = (diff_price/vm_price)*100
        else:
            diff_price = None
            perc_diff_price = None

        print('Product name TaxFree: {}'.format(tf_name))
        print('Product price TaxFree: {}.00'.format(tf_price))
        print('Product name Vinmonopolet: {}'.format(vm_name))
        print('Product price Vinmonopolet: {}'.format(vm_price))

        print('')
        print('************************************')

        cursor.execute('''INSERT INTO products(timestamp, barcode, category, sub_category, tf_name, vm_name, tf_price, vm_price, diff_price, perc_diff_price)
                          VALUES(?,?,?,?,?,?,?,?,?,?)''', (datetime.datetime.now().isoformat(), tf_barcode, tf_search_category, tf_search_sub_category, tf_name, vm_name, tf_price, vm_price, diff_price, perc_diff_price))
        db.commit()


vm = Vinmonopolet()
tf = TaxFree()

db = sqlite3.connect('database')
cursor = db.cursor()


for vine_type in ['Rødvin', 'Hvitvin', 'Rosévin', 'Dessertvin', 'Musserende', 'Sterkvin', 'Per<NAME>']:
    category = 'vin'
    tf_search = tf.search('', category, vine_type)
    lookup_and_store_search(tf_search, category, vine_type)

for fortified_vine_type in ['Aperitiff', 'Bitter', 'Eplebrennevin', 'Grappa', 'Tequila & Mezcal', 'Likør', 'Akevitt', 'Brandy', 'Cognac', 'Gin', 'Rom', 'Vodka', 'Armagnac', 'Whisky', 'Brennevin under 22%']:
    category = 'brennevin'
    tf_search = tf.search('', category, fortified_vine_type)
    lookup_and_store_search(tf_search, category, fortified_vine_type)

for beer_type in ['Lager og pils', 'Hveteøl', 'Ale', 'Belgisk stil', 'Stout og porter', 'Sider', 'Øvrige']:
    category = 'øl'
    tf_search = tf.search('', category, beer_type)
    lookup_and_store_search(tf_search, category, beer_type)

db.close()
