2019-06-16 23:54:10 -05:00
|
|
|
from grocy.entity import Entity
|
|
|
|
import re
|
|
|
|
from grocy.conf import Configuration
|
|
|
|
import logging
|
2019-06-22 02:21:23 -05:00
|
|
|
|
2019-06-16 23:54:10 -05:00
|
|
|
from tabulate import tabulate
|
|
|
|
|
|
|
|
|
|
|
|
class Table(object):
|
|
|
|
NOT_ENOUGH_IN_STOCK_MSG = '{glyph} Not enough in stock, {missing_amount} ingredient{s} missing'
|
|
|
|
ENOUGH_IN_STOCK_MSG = '{glyph} Enough in stock'
|
|
|
|
NOT_ENOUGH_BUT_IN_SHOPPING_LIST_MSG = '{not_enough}, but already on list'.format(not_enough=NOT_ENOUGH_IN_STOCK_MSG)
|
|
|
|
|
|
|
|
def __init__(self, **entries):
|
|
|
|
self.__dict__.update(entries)
|
|
|
|
self.conf = Configuration()
|
|
|
|
self.conf.load()
|
|
|
|
|
2019-06-22 02:21:23 -05:00
|
|
|
@property
|
|
|
|
def product(self):
|
|
|
|
if not self.entry:
|
|
|
|
raise Exception('Missing product')
|
2019-07-07 13:58:01 -05:00
|
|
|
loaded_template = self.conf.templates('product/view')
|
2019-06-22 02:21:23 -05:00
|
|
|
return loaded_template.render(self.entry)
|
|
|
|
|
2019-06-25 00:52:17 -05:00
|
|
|
@property
|
|
|
|
def products(self):
|
|
|
|
if not self.entries:
|
|
|
|
raise Exception('Missing entries')
|
|
|
|
product_groups_map = {product_group['id']: product_group['name']
|
|
|
|
for product_group in self.entries['product_groups']}
|
|
|
|
location_map = {location['id']: location['name']
|
|
|
|
for location in self.entries['locations']}
|
|
|
|
quantity_unit_map = {quantity_unit['id']: quantity_unit['name']
|
|
|
|
for quantity_unit in self.entries['quantity_units']}
|
|
|
|
table_entries = []
|
|
|
|
try:
|
|
|
|
for entry in self.entries['products']:
|
|
|
|
table_entry = []
|
|
|
|
|
2019-07-07 13:58:01 -05:00
|
|
|
product_group_name = 'N/A' if entry['product_group_id'] == '' else product_groups_map[entry['product_group_id']]
|
|
|
|
mini_stock_amount = entry['mini_stock_amount'] if 'mini_stock_amount' in entry else 'N/A'
|
|
|
|
qu_factor_purchase_to_stock = entry['qu_factor_purchase_to_stock'] if 'qu_factor_purchase_to_stock' in entry else 'N/A'
|
|
|
|
location_name = location_map[entry['location_id']] if 'location_id' in entry else 'N/A'
|
|
|
|
quantity_unit_purchase_name = quantity_unit_map[entry['qu_id_purchase']] if 'qu_id_purchase' in entry else 'N/A'
|
|
|
|
quantity_unit_stock_name = quantity_unit_map[entry['qu_id_stock']] if 'qu_id_stock' in entry else 'N/A'
|
|
|
|
|
2019-06-25 00:52:17 -05:00
|
|
|
table_entry.append(entry['id'])
|
2019-07-07 13:58:01 -05:00
|
|
|
table_entry.append(entry['name'])
|
2019-06-25 00:52:17 -05:00
|
|
|
table_entry.append(location_name)
|
|
|
|
table_entry.append(quantity_unit_purchase_name)
|
|
|
|
table_entry.append(quantity_unit_stock_name)
|
|
|
|
table_entry.append(product_group_name)
|
2019-07-07 13:58:01 -05:00
|
|
|
table_entry.append(mini_stock_amount)
|
|
|
|
table_entry.append(quantity_unit_stock_name)
|
2019-06-25 00:52:17 -05:00
|
|
|
table_entries.append(table_entry)
|
2019-07-07 13:58:01 -05:00
|
|
|
table_headers = ['ID', 'Name', 'Location', 'Min\nStock Amount',
|
|
|
|
'QU\nPurchase', 'QU\nStock', 'QU\nFactor', 'Product\nGroup']
|
2019-06-25 00:52:17 -05:00
|
|
|
return tabulate(table_entries, headers=table_headers)
|
|
|
|
except Exception as e:
|
|
|
|
raise e
|
|
|
|
|
2019-06-16 23:54:10 -05:00
|
|
|
@property
|
|
|
|
def stock(self):
|
|
|
|
logger = logging.getLogger('table.stock')
|
|
|
|
entity = Entity(name='products')
|
|
|
|
products = entity.get()
|
|
|
|
products_map = {product['id']: product for product in products}
|
|
|
|
try:
|
|
|
|
# Get product names from ids and replace
|
|
|
|
table_entries = []
|
|
|
|
try:
|
|
|
|
for item in self.stocks:
|
|
|
|
product = products_map[item['product_id']]
|
|
|
|
item['product_id'] = product['name']
|
|
|
|
table_entry = list(dict.values(item))
|
|
|
|
table_entries.append(table_entry)
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
raise e
|
|
|
|
|
|
|
|
# Generate stock overview table
|
|
|
|
table_headers = ['Product', 'Amount', 'Best Before Date', 'Amount Opened']
|
|
|
|
return tabulate(table_entries, headers=table_headers)
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
raise e
|
|
|
|
|
|
|
|
@property
|
|
|
|
def recipe(self):
|
|
|
|
checkmark_glyph = ''
|
|
|
|
times_glyph = ''
|
|
|
|
exclamation_glyph = ''
|
2019-07-07 13:58:01 -05:00
|
|
|
logger = logging.getLogger('table.recipe')
|
|
|
|
normal_recipes = [recipe for recipe in self.recipes if re.search(r'^normal', recipe['type'])]
|
|
|
|
recipes_req_map = {recipe_reqs['recipe_id']: recipe_reqs for recipe_reqs in self.recipes_reqs}
|
|
|
|
|
|
|
|
try:
|
|
|
|
table_entries = []
|
|
|
|
try:
|
|
|
|
for item in normal_recipes:
|
|
|
|
table_entry = []
|
|
|
|
table_entry.append(item['id'])
|
|
|
|
table_entry.append(item['name'])
|
|
|
|
table_entry.append(item['base_servings'])
|
|
|
|
|
|
|
|
recipe_reqs = recipes_req_map[item['id']]
|
|
|
|
missing_amount = int(recipe_reqs['missing_products_count'])
|
|
|
|
number_of_ingredients = 's' if missing_amount > 1 else ''
|
|
|
|
if recipe_reqs['need_fulfilled'] == '1':
|
|
|
|
table_entry.append(self.ENOUGH_IN_STOCK_MSG.format(glyph=checkmark_glyph))
|
|
|
|
elif recipe_reqs['need_fulfilled_with_shopping_list'] == '1':
|
|
|
|
missing_amount = recipe_reqs['missing_products_count']
|
|
|
|
table_entry.append(self.NOT_ENOUGH_BUT_IN_SHOPPING_LIST_MSG.format(glyph=exclamation_glyph,
|
|
|
|
missing_amount=missing_amount, s=number_of_ingredients))
|
|
|
|
else:
|
|
|
|
table_entry.append(self.NOT_ENOUGH_IN_STOCK_MSG.format(glyph=times_glyph,
|
|
|
|
missing_amount=missing_amount, s=number_of_ingredients))
|
|
|
|
table_entries.append(table_entry)
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
raise e
|
|
|
|
|
|
|
|
# Generate recipes overview table
|
|
|
|
table_headers = ['Id', 'Name', 'Servings', 'Requirements Fulfilled']
|
|
|
|
return tabulate(table_entries, headers=table_headers)
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
raise e
|
|
|
|
@property
|
|
|
|
def recipes(self):
|
|
|
|
checkmark_glyph = ''
|
|
|
|
times_glyph = ''
|
|
|
|
exclamation_glyph = ''
|
|
|
|
logger = logging.getLogger('table.recipe')
|
2019-06-16 23:54:10 -05:00
|
|
|
normal_recipes = [recipe for recipe in self.recipes if re.search(r'^normal', recipe['type'])]
|
|
|
|
recipes_req_map = {recipe_reqs['recipe_id']: recipe_reqs for recipe_reqs in self.recipes_reqs}
|
|
|
|
|
|
|
|
try:
|
|
|
|
table_entries = []
|
|
|
|
try:
|
|
|
|
for item in normal_recipes:
|
|
|
|
table_entry = []
|
|
|
|
table_entry.append(item['id'])
|
|
|
|
table_entry.append(item['name'])
|
|
|
|
table_entry.append(item['base_servings'])
|
|
|
|
|
|
|
|
recipe_reqs = recipes_req_map[item['id']]
|
|
|
|
missing_amount = int(recipe_reqs['missing_products_count'])
|
|
|
|
number_of_ingredients = 's' if missing_amount > 1 else ''
|
|
|
|
if recipe_reqs['need_fulfilled'] == '1':
|
|
|
|
table_entry.append(self.ENOUGH_IN_STOCK_MSG.format(glyph=checkmark_glyph))
|
|
|
|
elif recipe_reqs['need_fulfilled_with_shopping_list'] == '1':
|
|
|
|
missing_amount = recipe_reqs['missing_products_count']
|
|
|
|
table_entry.append(self.NOT_ENOUGH_BUT_IN_SHOPPING_LIST_MSG.format(glyph=exclamation_glyph,
|
|
|
|
missing_amount=missing_amount, s=number_of_ingredients))
|
|
|
|
else:
|
|
|
|
table_entry.append(self.NOT_ENOUGH_IN_STOCK_MSG.format(glyph=times_glyph,
|
|
|
|
missing_amount=missing_amount, s=number_of_ingredients))
|
|
|
|
table_entries.append(table_entry)
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
raise e
|
|
|
|
|
|
|
|
# Generate recipes overview table
|
|
|
|
table_headers = ['Id', 'Name', 'Servings', 'Requirements Fulfilled']
|
|
|
|
return tabulate(table_entries, headers=table_headers)
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
raise e
|
|
|
|
|
|
|
|
@property
|
|
|
|
def shopping_list(self):
|
|
|
|
logger = logging.getLogger('table.shopping_list')
|
|
|
|
try:
|
|
|
|
table_headers = ['Group', 'Product', 'Amount']
|
|
|
|
# Get product names and location from ids and replace
|
|
|
|
product_ids = [entry['product_id'] for entry in self.shopping_list]
|
|
|
|
products = []
|
|
|
|
location_ids = []
|
|
|
|
table_entries = []
|
|
|
|
for index in range(len(product_ids)):
|
|
|
|
product_id = product_ids[index]
|
|
|
|
entity = Entity(name='products')
|
|
|
|
product = entity.get(id=product_id)
|
|
|
|
|
|
|
|
entity = Entity(name='quantity_units')
|
|
|
|
quantity_unit = entity.get(product['qu_id_purchase'])
|
|
|
|
|
|
|
|
min_amount = '{} {}'.format(product['min_stock_amount'], quantity_unit['name'])
|
|
|
|
if product['product_group_id'] == '':
|
|
|
|
product_group_name = 'Uncategorized'
|
|
|
|
else:
|
|
|
|
entity = Entity(name='product_groups')
|
|
|
|
product_group = product.get(id=product['product_group_id'])
|
|
|
|
product_group_name = product_group['name']
|
|
|
|
shopping_item = [product_group_name, product['name'], min_amount]
|
|
|
|
table_entries.append(shopping_item)
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
raise e
|
|
|
|
|
|
|
|
# Generate stock overview table
|
|
|
|
return tabulate(table_entries, headers=table_headers)
|
2019-07-07 13:58:01 -05:00
|
|
|
|
|
|
|
|