feat: Added templates for macro, list, and view for recipe
- feat: Added list and view commands for recipe
This commit is contained in:
parent
6af9bef334
commit
05089108a9
12
file.txt
12
file.txt
@ -1,12 +0,0 @@
|
|||||||
1. Preheat oven to 425 degrees F (220 degrees C). Lightly oil a large roasting pan.
|
|
||||||
2. Place chicken pieces in large bowl. Season with salt, oregano, pepper, rosemary, and cayenne pepper. Add fresh lemon juice, olive oil, and garlic. Place potatoes in bowl with the chicken; stir together until chicken and potatoes are evenly coated with marinade.
|
|
||||||
3. Transfer chicken pieces, skin side up, to prepared roasting pan, reserving marinade. Distribute potato pieces among chicken thighs. Drizzle with 2/3 cup chicken broth. Spoon remainder of marinade over chicken and potatoes.
|
|
||||||
4. Place in preheated oven. Bake in the preheated oven for 20 minutes. Toss chicken and potatoes, keeping chicken skin side up; continue baking until chicken is browned and cooked through, about 25 minutes more. An instant-read thermometer inserted near the bone should read 165 degrees F (74 degrees C). Transfer chicken to serving platter and keep warm.
|
|
||||||
5. Set oven to broil or highest heat setting. Toss potatoes once again in pan juices. Place pan under broiler and broil until potatoes are caramelized, about 3 minutes. Transfer potatoes to serving platter with chicken.
|
|
||||||
6. Place roasting pan on stove over medium heat. Add a splash of broth and stir up browned bits from the bottom of the pan. Strain; spoon juices over chicken and potatoes. Top with chopped oregano.
|
|
||||||
|
|
||||||
[](/"https://www.allrecipes.com/recipe/242352/greek-lemon-chicken-and-
|
|
||||||
potatoes//")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
192
grocy/cli.py
192
grocy/cli.py
@ -23,6 +23,7 @@ CONFIG_DIR = click.get_app_dir(APP_NAME)
|
|||||||
PROJ_DIR = path.join(path.dirname(path.realpath(__file__)))
|
PROJ_DIR = path.join(path.dirname(path.realpath(__file__)))
|
||||||
TEMPLATE_LOADER = Environment(loader=FileSystemLoader('templates'), trim_blocks=True, lstrip_blocks=True)
|
TEMPLATE_LOADER = Environment(loader=FileSystemLoader('templates'), trim_blocks=True, lstrip_blocks=True)
|
||||||
|
|
||||||
|
|
||||||
class GrocyGroup(click.Group):
|
class GrocyGroup(click.Group):
|
||||||
def parse_args(self, ctx, args):
|
def parse_args(self, ctx, args):
|
||||||
is_subcommand = True if args[0] in self.commands else False
|
is_subcommand = True if args[0] in self.commands else False
|
||||||
@ -97,6 +98,7 @@ def view(ctx, product_id):
|
|||||||
logger.error(e)
|
logger.error(e)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
|
||||||
@product.command()
|
@product.command()
|
||||||
@click.option('--name', '-n', 'name')
|
@click.option('--name', '-n', 'name')
|
||||||
@click.argument('product_id', required=False)
|
@click.argument('product_id', required=False)
|
||||||
@ -124,7 +126,7 @@ def edit(product_id, name):
|
|||||||
if edited_products is None:
|
if edited_products is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
parsed_edited_products = Util.load_yaml(edited_products)
|
parsed_edited_products = util.load_yaml(edited_products)
|
||||||
schema = entity.schema
|
schema = entity.schema
|
||||||
|
|
||||||
for index, edited_product in enumerate(parsed_edited_products):
|
for index, edited_product in enumerate(parsed_edited_products):
|
||||||
@ -154,6 +156,8 @@ def list(name, template):
|
|||||||
# Convert name args to a single string
|
# Convert name args to a single string
|
||||||
string_name_arg = ' '.join(name) if type(name) == list else name
|
string_name_arg = ' '.join(name) if type(name) == list else name
|
||||||
products = product_entity.find({'name': string_name_arg})
|
products = product_entity.find({'name': string_name_arg})
|
||||||
|
if len(products) == 0:
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
products = product_entity.get()
|
products = product_entity.get()
|
||||||
|
|
||||||
@ -193,16 +197,23 @@ def add(template):
|
|||||||
logger = logging.getLogger('cli.product.add')
|
logger = logging.getLogger('cli.product.add')
|
||||||
meta = Meta()
|
meta = Meta()
|
||||||
# Get product_groups
|
# Get product_groups
|
||||||
meta.add(type='entities', name='product_groups')
|
entity = Entity(name='product_groups')
|
||||||
|
product_groups = entity.get()
|
||||||
|
meta.add(type='entities', name='product_groups', valid_values=product_groups)
|
||||||
# Get locations
|
# Get locations
|
||||||
meta.add(type='entities', name='locations')
|
entity = Entity(name='locations')
|
||||||
|
locations = entity.get()
|
||||||
|
meta.add(type='entities', name='locations', valid_values=locations)
|
||||||
# Get quantity_units
|
# Get quantity_units
|
||||||
meta.add(type='entities', name='quantity_units')
|
entity = Entity(name='quantity_units')
|
||||||
|
quantity_units = entity.get()
|
||||||
|
meta.add(type='entities', name='quantity_units', valid_values=quantity_units)
|
||||||
|
data = { 'meta': meta.generate() }
|
||||||
if template:
|
if template:
|
||||||
loaded_template = cfg.templates(template)
|
loaded_template = cfg.templates(template)
|
||||||
else:
|
else:
|
||||||
loaded_template = cfg.templates('product/add')
|
loaded_template = cfg.templates('product/add')
|
||||||
new_product = click.edit(loaded_template.render(grocy=meta.generate()), extension='.yml')
|
new_product = click.edit(loaded_template.render(grocy=data), extension='.yml')
|
||||||
|
|
||||||
if not new_product:
|
if not new_product:
|
||||||
return
|
return
|
||||||
@ -222,6 +233,7 @@ def add(template):
|
|||||||
def recipe(ctx):
|
def recipe(ctx):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@recipe.command()
|
@recipe.command()
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@click.argument('recipe_id', required=False)
|
@click.argument('recipe_id', required=False)
|
||||||
@ -234,7 +246,10 @@ def view(ctx, recipe_id, template):
|
|||||||
data = {'fields': {}}
|
data = {'fields': {}}
|
||||||
if recipe_id:
|
if recipe_id:
|
||||||
entity = Entity(name='recipes')
|
entity = Entity(name='recipes')
|
||||||
|
meta = Meta()
|
||||||
data['fields'] = entity.get(id=recipe_id)
|
data['fields'] = entity.get(id=recipe_id)
|
||||||
|
recipe = Recipe(id=recipe_id)
|
||||||
|
data['fields']['fulfillment'] = recipe.fulfillment
|
||||||
|
|
||||||
# Change html markup to plain text
|
# Change html markup to plain text
|
||||||
html_markup_description = data['fields']['description']
|
html_markup_description = data['fields']['description']
|
||||||
@ -242,35 +257,147 @@ def view(ctx, recipe_id, template):
|
|||||||
data['fields']['description'] = plain_text_description
|
data['fields']['description'] = plain_text_description
|
||||||
|
|
||||||
recipe = Recipe(id=recipe_id)
|
recipe = Recipe(id=recipe_id)
|
||||||
data['fields']['fulfillment'] = recipe.get_fulfillments()
|
meta.add(type='recipes', name='ingredients', valid_values=recipe.ingredients)
|
||||||
|
|
||||||
|
data['meta'] = meta.generate()
|
||||||
|
|
||||||
if template:
|
if template:
|
||||||
loaded_template = cfg.templates(template)
|
loaded_template = cfg.templates(template)
|
||||||
else:
|
else:
|
||||||
loaded_template = cfg.templates('recipe/view')
|
loaded_template = cfg.templates('recipe/view')
|
||||||
|
|
||||||
entity = Entity(name='recipes')
|
|
||||||
click.echo(loaded_template.render(grocy=data))
|
click.echo(loaded_template.render(grocy=data))
|
||||||
else:
|
else:
|
||||||
click.echo(ctx.get_help())
|
click.echo(ctx.get_help())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
raise e
|
raise e
|
||||||
#@recipe.command()
|
|
||||||
#def list():
|
@recipe.command()
|
||||||
# logger = logging.getLogger('cli.recipe')
|
@click.option('--name', '-n', 'name')
|
||||||
# try:
|
@click.option('-t', 'template')
|
||||||
# entity = Entity(name='recipes')
|
def list(name, template):
|
||||||
# recipes = entity.get()
|
logger = logging.getLogger('cli.recipe.list')
|
||||||
# recipe = Recipe(
|
cfg = Configuration()
|
||||||
# ingredient_reqs = recipe.get_ingredient_requirements()
|
cfg.load()
|
||||||
# table = Table(recipes=recipes, recipes_reqs=recipes_reqs, ingredient_reqs=ingredient_reqs)
|
try:
|
||||||
# click.echo(table.recipe)
|
entity = Entity(name='recipes')
|
||||||
# except Exception as e:
|
if name:
|
||||||
# logger.error(e)
|
# Convert name args to a single string
|
||||||
# raise e
|
string_name_arg = ' '.join(name) if type(name) == list else name
|
||||||
##
|
recipe_entities = entity.find({'name': string_name_arg})
|
||||||
#
|
if len(recipe_entities) == 0:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
recipe_entities = entity.get()
|
||||||
|
|
||||||
|
data = {'recipes': []}
|
||||||
|
for recipe_entity in recipe_entities:
|
||||||
|
entry = {'fields': recipe_entity, 'meta': []}
|
||||||
|
meta = Meta(include_fa_icons=False)
|
||||||
|
recipe = Recipe(id=recipe_entity['id'])
|
||||||
|
entry['fields']['fulfillment'] = recipe.fulfillment
|
||||||
|
entry['fields']['description'] = recipe.generate_plain_text_description(recipe_entity['description'])
|
||||||
|
|
||||||
|
meta.add(type='recipes', name='ingredients', valid_values=recipe.ingredients)
|
||||||
|
entry['meta'].append(meta.generate())
|
||||||
|
data['recipes'].append(entry)
|
||||||
|
|
||||||
|
meta = Meta()
|
||||||
|
data['meta'] = meta.generate()
|
||||||
|
if template:
|
||||||
|
loaded_template = cfg.templates(template)
|
||||||
|
else:
|
||||||
|
loaded_template = cfg.templates('recipe/list')
|
||||||
|
|
||||||
|
click.echo(loaded_template.render(grocy=data))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
@recipe.command()
|
||||||
|
@click.option('--fullscreen', '-f', 'fullscreen', is_flag=True)
|
||||||
|
@click.argument('recipe_id')
|
||||||
|
def browse(fullscreen, recipe_id):
|
||||||
|
logger = logging.getLogger('cli.recipe.browse')
|
||||||
|
try:
|
||||||
|
cfg = Configuration()
|
||||||
|
cfg.load()
|
||||||
|
url = '{domain}/recipes?recipe={recipe_id}'.format(domain=cfg.domain, recipe_id=recipe_id)
|
||||||
|
if fullscreen:
|
||||||
|
url += '#fullscreen'
|
||||||
|
click.launch(url, wait=False)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
|
||||||
|
|
||||||
|
@recipe.command()
|
||||||
|
@click.option('--name', '-n', 'name')
|
||||||
|
@click.argument('recipe_id', required=False)
|
||||||
|
@click.option('-t', 'template')
|
||||||
|
def edit(recipe_id, name, template):
|
||||||
|
logger = logging.getLogger('cli.recipe.edit')
|
||||||
|
try:
|
||||||
|
cfg = Configuration()
|
||||||
|
util = Util(cfg=cfg)
|
||||||
|
cfg.load()
|
||||||
|
loaded_template = cfg.templates('recipe/edit')
|
||||||
|
if template:
|
||||||
|
loaded_template = cfg.templates(template)
|
||||||
|
else:
|
||||||
|
loaded_template = cfg.templates('recipe/list')
|
||||||
|
|
||||||
|
entity = Entity(name='recipes')
|
||||||
|
if recipe_id:
|
||||||
|
recipe_entity = entity.get(id=recipe_id)
|
||||||
|
recipe = Recipe(id=recipe_id)
|
||||||
|
entry = {'fields': recipe_entity}
|
||||||
|
meta = Meta()
|
||||||
|
entry['fields']['fulfillment'] = recipe.fulfillment
|
||||||
|
entry['fields']['description'] = recipe.generate_plain_text_description(entity['description'])
|
||||||
|
entry['meta'] = meta.generate()
|
||||||
|
edited_recipe = click.edit(loaded_template.render(grocy=entry))
|
||||||
|
edited_recipe.update()
|
||||||
|
return
|
||||||
|
elif name:
|
||||||
|
# Convert name args to a single string
|
||||||
|
string_name_arg = ' '.join(name) if type(name) == list else name
|
||||||
|
recipe_entities = entity.find({'name': string_name_arg})
|
||||||
|
if len(recipe_entities) == 0:
|
||||||
|
click.echo('Could not find recipe')
|
||||||
|
return
|
||||||
|
|
||||||
|
data = {'recipes': []}
|
||||||
|
for recipe_entity in recipe_entities:
|
||||||
|
entry = {'fields': recipe_entity, 'meta': []}
|
||||||
|
meta = Meta(include_fa_icons=False)
|
||||||
|
recipe = Recipe(id=recipe_entity['id'])
|
||||||
|
entry['fields']['fulfillment'] = recipe.fulfillment
|
||||||
|
entry['fields']['description'] = recipe.generate_plain_text_description(recipe_entity['description'])
|
||||||
|
|
||||||
|
meta.add(type='recipes', name='ingredients', valid_values=recipe.ingredients)
|
||||||
|
entry['meta'].append(meta.generate())
|
||||||
|
data['recipes'].append(entry)
|
||||||
|
|
||||||
|
meta = Meta()
|
||||||
|
data['meta'] = meta.generate()
|
||||||
|
edited_recipes = click.edit(loaded_template.render(grocy=data))
|
||||||
|
if edited_recipes is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
parsed_edited_recipes = util.load_yaml(edited_recipes)
|
||||||
|
for index, edited_recipe in enumerate(parsed_edited_recipes):
|
||||||
|
edited_recipe['id'] = recipe_entities[index]['id']
|
||||||
|
# Util.verify_integrity(edited_recipe, schema)
|
||||||
|
entity.update(edited_recipe, id=recipe[index]['id'])
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise click.BadParameter('Missing RECIPE_ID or QUERY')
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
#@main.command()
|
#@main.command()
|
||||||
#def shopping():
|
#def shopping():
|
||||||
# logger = logging.getLogger('cli.shopping')
|
# logger = logging.getLogger('cli.shopping')
|
||||||
@ -337,27 +464,6 @@ def view(ctx, recipe_id, template):
|
|||||||
# raise e
|
# raise e
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#@recipe.command('edit')
|
|
||||||
#@click.argument('recipe_id')
|
|
||||||
#def edit(recipe_id):
|
|
||||||
# logger = logging.getLogger('cli.recipe.edit')
|
|
||||||
# try:
|
|
||||||
# if recipe_id:
|
|
||||||
# entity = Entity(name='recipes')
|
|
||||||
# recipe = entity.get(id=recipe_id)
|
|
||||||
# loaded_template = TEMPLATE_LOADER.get_template('recipe_edit.yml')
|
|
||||||
# edited_recipe = click.edit(loaded_template.render(recipe))
|
|
||||||
# if edited_recipe is not None:
|
|
||||||
# parsed_edited_recipe = yaml.safe_load(edited_recipe)
|
|
||||||
# parsed_edited_recipe['description'] = markdown(parsed_edited_recipe['description'])
|
|
||||||
# recipe.__dict__.update(parsed_edited_recipe)
|
|
||||||
# recipe.update()
|
|
||||||
# except Exception as e:
|
|
||||||
# logger.error(e)
|
|
||||||
# logger.error('Could not edit recipe {}'.format(recipe_id))
|
|
||||||
# raise e
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#@recipe.command('create')
|
#@recipe.command('create')
|
||||||
#@click.pass_context
|
#@click.pass_context
|
||||||
#def create(ctx):
|
#def create(ctx):
|
||||||
|
@ -99,7 +99,7 @@ class Configuration(object):
|
|||||||
def templates(self, name):
|
def templates(self, name):
|
||||||
try:
|
try:
|
||||||
TEMPLATE_LOADER = Environment(loader=FileSystemLoader([self.USER_TEMPLATE_DIR, self.PROJ_TEMPLATE_DIR]),
|
TEMPLATE_LOADER = Environment(loader=FileSystemLoader([self.USER_TEMPLATE_DIR, self.PROJ_TEMPLATE_DIR]),
|
||||||
trim_blocks=False, lstrip_blocks=True)
|
trim_blocks=False, lstrip_blocks=True, keep_trailing_newline=False)
|
||||||
|
|
||||||
return TEMPLATE_LOADER.get_template('{}.{}'.format(name, self.TEMPLATE_EXT))
|
return TEMPLATE_LOADER.get_template('{}.{}'.format(name, self.TEMPLATE_EXT))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -2,7 +2,6 @@ from grocy.request import Request
|
|||||||
import re
|
import re
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from grocy.conf import Configuration
|
from grocy.conf import Configuration
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
@ -51,7 +50,7 @@ class Entity(object):
|
|||||||
found_entities.append(entity)
|
found_entities.append(entity)
|
||||||
|
|
||||||
if len(found_entities) == 0:
|
if len(found_entities) == 0:
|
||||||
return None
|
return []
|
||||||
|
|
||||||
return found_entities
|
return found_entities
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -5,23 +5,21 @@ from fontawesome import icons as fa_icons
|
|||||||
|
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
def __init__(self):
|
def __init__(self, include_fa_icons=True):
|
||||||
self.meta = {'meta': {'entities': {}, 'fa_icons': fa_icons}}
|
self.meta = {}
|
||||||
|
if include_fa_icons:
|
||||||
|
self.meta['fa_icons'] = fa_icons
|
||||||
|
|
||||||
def add(self, type, name):
|
def add(self, type, name=None, ids=[], valid_values=None):
|
||||||
if type == 'entities':
|
if type not in self.meta:
|
||||||
entity = Entity(name=name)
|
self.meta[type] = {}
|
||||||
resources = entity.get()
|
if name and name not in self.meta[type]:
|
||||||
schema = get_schema(name)
|
self.meta[type][name] = {}
|
||||||
elif type == 'recipes':
|
#if name:
|
||||||
recipe = Recipe()
|
# schema = get_schema(name)
|
||||||
if name == 'fulfillments':
|
#if type == 'entities':
|
||||||
resources = recipe.get_fulfillments()
|
#self.meta[type][name]['properties'] = schema['properties']
|
||||||
schema = get_schema(name='recipe_fulfilments')
|
self.meta[type][name]['valid_values'] = valid_values
|
||||||
|
|
||||||
self.meta['meta'][type][name] = {}
|
|
||||||
self.meta['meta'][type][name]['properties'] = schema['properties']
|
|
||||||
self.meta['meta'][type][name]['valid_values'] = resources
|
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
return self.meta
|
return self.meta
|
||||||
|
102
grocy/recipe.py
102
grocy/recipe.py
@ -1,5 +1,8 @@
|
|||||||
from grocy.request import Request
|
from grocy.request import Request
|
||||||
|
from html2text import html2text
|
||||||
|
from grocy.stock import Stock
|
||||||
from grocy.conf import Configuration
|
from grocy.conf import Configuration
|
||||||
|
from copy import deepcopy
|
||||||
from grocy.entity import Entity
|
from grocy.entity import Entity
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -7,17 +10,87 @@ import logging
|
|||||||
class Recipe(object):
|
class Recipe(object):
|
||||||
GET_RECIPES_FULFILLMENT_URL_TEMPLATE = '{domain}/api/recipes/fulfillment'
|
GET_RECIPES_FULFILLMENT_URL_TEMPLATE = '{domain}/api/recipes/fulfillment'
|
||||||
GET_RECIPE_FULFILLMENT_URL_TEMPLATE = '{domain}/api/recipes/{recipeId}/fulfillment'
|
GET_RECIPE_FULFILLMENT_URL_TEMPLATE = '{domain}/api/recipes/{recipeId}/fulfillment'
|
||||||
GET_RECIPES_POS_FULFILLMENT_URL_TEMPLATE = '{domain}/api/recipes/pos/fulfillment'
|
GET_RECIPES_POS_FULFILLMENT_URL_TEMPLATE = '{domain}/api/recipes/{recipeId}/pos/fulfillment'
|
||||||
GET_RECIPE_POS_FULFILLMENT_URL_TEMPLATE = '{domain}/api/recipes/{recipeId}/pos/{recipeId}/fulfillment'
|
GET_RECIPE_POS_FULFILLMENT_URL_TEMPLATE = '{domain}/api/recipes/{recipeId}/pos/{recipePosId}/fulfillment'
|
||||||
|
|
||||||
def __init__(self, id=None):
|
def __init__(self, id=None):
|
||||||
self.conf = Configuration()
|
self.conf = Configuration()
|
||||||
self.conf.load()
|
self.conf.load()
|
||||||
self.id = id
|
self.id = id
|
||||||
|
|
||||||
def get_ingredient_requirements(self, recipe_id=None):
|
@property
|
||||||
logger = logging.getLogger('recipe.get_ingredient_requirements')
|
def ingredients(self):
|
||||||
|
logger = logging.getLogger('recipes.ingredients')
|
||||||
|
|
||||||
|
stock = Stock()
|
||||||
|
ingredients_detail = []
|
||||||
|
products = Entity(name='products').get()
|
||||||
|
locations = Entity(name='locations').get()
|
||||||
|
quantity_units = Entity(name='quantity_units').get()
|
||||||
|
for recipe_pos in self.pos_fulfillment:
|
||||||
|
if recipe_pos['recipe_id'] == self.id:
|
||||||
|
data = {}
|
||||||
|
product = next((p for p in products if p['id'] == recipe_pos['product_id']), None)
|
||||||
|
product['quantity_unit'] = next((q for q in quantity_units if q['id'] == recipe_pos['qu_id']), None)
|
||||||
|
product['location'] = next((l for l in locations if l['id'] == product['location_id']), None)
|
||||||
|
product['group'] = recipe_pos['ingredient_group']
|
||||||
|
|
||||||
|
|
||||||
|
# Remove extraneous properties
|
||||||
|
recipe_pos.pop('recipe_id', None)
|
||||||
|
recipe_pos.pop('ingredient_group', None)
|
||||||
|
recipe_pos.pop('id', None)
|
||||||
|
recipe_pos.pop('product_id', None)
|
||||||
|
recipe_pos.pop('recipe_pos_id', None)
|
||||||
|
recipe_pos.pop('qu_id', None)
|
||||||
|
product.pop('qu_id_purchase', None)
|
||||||
|
product.pop('qu_id_stock', None)
|
||||||
|
product.pop('location_id', None)
|
||||||
|
product['location'].pop('row_created_timestamp', None)
|
||||||
|
product['quantity_unit'].pop('row_created_timestamp', None)
|
||||||
|
product.pop('row_created_timestamp', None)
|
||||||
|
|
||||||
|
# Merge recipe pos and products
|
||||||
|
product.update(recipe_pos)
|
||||||
|
data.update(product)
|
||||||
|
ingredients_detail.append(data)
|
||||||
|
|
||||||
|
return ingredients_detail
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pos_fulfillment(self):
|
||||||
|
logger = logging.getLogger('recipe.pos_fulfillment')
|
||||||
|
try:
|
||||||
|
if self.id is None:
|
||||||
|
raise Exception('recipe id is required')
|
||||||
|
url = self.GET_RECIPES_POS_FULFILLMENT_URL_TEMPLATE.format(domain=self.conf.domain, recipeId=self.id)
|
||||||
|
request = Request('get', url)
|
||||||
|
return request.send()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def generate_plain_text_description(self, description):
|
||||||
|
if not description:
|
||||||
|
raise Exception('Missing description')
|
||||||
|
logger = logging.getLogger('recipe.generate_plain_text_description')
|
||||||
|
try:
|
||||||
|
plain_text_description = html2text(description)
|
||||||
|
return plain_text_description
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
raise e
|
||||||
|
@property
|
||||||
|
def fulfillment(self):
|
||||||
|
logger = logging.getLogger('recipe.fulfillment')
|
||||||
|
url = self.GET_RECIPE_FULFILLMENT_URL_TEMPLATE.format(domain=self.conf.domain, recipeId=self.id)
|
||||||
|
request = Request('get', url)
|
||||||
|
try:
|
||||||
|
return request.send()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
def get_fulfillments(self):
|
def get_fulfillments(self):
|
||||||
logger = logging.getLogger('recipe.get_requirements')
|
logger = logging.getLogger('recipe.get_requirements')
|
||||||
@ -31,24 +104,3 @@ class Recipe(object):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
def get(self):
|
|
||||||
# Get list of available ingredients
|
|
||||||
if self.id:
|
|
||||||
entity = Entity(name='recipes')
|
|
||||||
recipe = entity.get(id=self.id)
|
|
||||||
|
|
||||||
if type(recipe) is list:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,11 +5,12 @@ import logging
|
|||||||
SCHEMA_URL_TEMPLATE = '{domain}/api/openapi/specification'
|
SCHEMA_URL_TEMPLATE = '{domain}/api/openapi/specification'
|
||||||
SCHEMA_MODEL_MAP = {
|
SCHEMA_MODEL_MAP = {
|
||||||
'products': 'Product',
|
'products': 'Product',
|
||||||
|
'product_details': 'ProductDetailsResponse',
|
||||||
'stock': 'StockEntry',
|
'stock': 'StockEntry',
|
||||||
'product_groups': 'ProductGroup',
|
'product_groups': 'ProductGroup',
|
||||||
'locations': 'Location',
|
'locations': 'Location',
|
||||||
'quantity_units': 'QuantityUnit',
|
'quantity_units': 'QuantityUnit',
|
||||||
'recipe_requirements': 'RecipeFulfilmentResponse'
|
'recipe_fulfillment': 'RecipeFulfillmentResponse'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,8 +11,7 @@ class Util(object):
|
|||||||
self.cfg = cfg
|
self.cfg = cfg
|
||||||
yaml.SafeLoader.add_constructor("tag:yaml.org,2002:python/unicode", _yaml_constructor)
|
yaml.SafeLoader.add_constructor("tag:yaml.org,2002:python/unicode", _yaml_constructor)
|
||||||
|
|
||||||
|
def load_yaml(self, data):
|
||||||
def load_yaml(data):
|
|
||||||
generator = yaml.safe_load_all(data)
|
generator = yaml.safe_load_all(data)
|
||||||
data_list = list(generator)
|
data_list = list(generator)
|
||||||
return data_list
|
return data_list
|
||||||
|
11
templates/recipe/list.yml
Normal file
11
templates/recipe/list.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% from 'recipe/macro.yml' import render_recipe_fulfilment %}
|
||||||
|
{% for recipe in grocy.recipes %}
|
||||||
|
name: {{ recipe.fields.name }}
|
||||||
|
servings: {{ recipe.fields.base_servings }}
|
||||||
|
required_fulfilled: {{ render_recipe_fulfilment(recipe.fields.fulfillment, grocy.meta.fa_icons) }}
|
||||||
|
description: |-
|
||||||
|
{{ recipe.fields.description }}
|
||||||
|
{% if loop.nextitem %}
|
||||||
|
---
|
||||||
|
{%endif%}
|
||||||
|
{%endfor %}
|
17
templates/recipe/macro.yml
Normal file
17
templates/recipe/macro.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{% macro render_stock_fulfilment(ingredient, fa_icons) -%}
|
||||||
|
{% if ingredient.need_fulfilled == "1" %} {{ 'Enough in stock' }} {{ fa_icons['check'] }}
|
||||||
|
{% elif ingredient.need_fulfilled_with_shopping_list == "1" %} {{ 'Not enough in stock, %s missing %s already in stock' | format(ingredient.missing_amount, ingredient.amount_on_shopping_list | int) }} {{ fa_icons['exclamation'] }}
|
||||||
|
{% else %} {{ 'Not enough in stock, %s missing' | format(ingredient.missing_amount) }} {{ fa_icons['times'] }}
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro render_recipe_fulfilment(recipe, fa_icons) -%}
|
||||||
|
{% if recipe.need_fulfilled == "1" %} {{ 'Enough in stock' }} {{ fa_icons['check'] }}
|
||||||
|
{% else %} {{ 'Not enough in stock, %s ingredients missing' | format(recipe.missing_products_count) }} {{ fa_icons['times'] }}
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro ingredient_label(ingredient) -%}
|
||||||
|
{{ ingredient.recipe_amount }} {% if ingredient.recipe_amount | int > 1 %} {{ ingredient.quantity_unit.name_plural }} {% else %} {{ ingredient.quantity_unit.name }} {% endif %} {{ ingredient.name }}
|
||||||
|
|
||||||
|
{%- endmacro %}
|
@ -1,17 +1,10 @@
|
|||||||
|
{% from 'recipe/macro.yml' import ingredient_label, render_stock_fulfilment %}
|
||||||
name: {{ grocy.fields.name }}
|
name: {{ grocy.fields.name }}
|
||||||
servings: {{ grocy.fields.base_servings }}
|
servings: {{ grocy.fields.base_servings }}
|
||||||
costs: {{ grocy.fields.fulfillment.costs }}
|
costs: {{ grocy.fields.fulfillment.costs }}
|
||||||
ingredients: {% for ingredient in grocy.fields.ingredients %}
|
ingredients: {% for ingredient in grocy.meta.recipes.ingredients.valid_values %}
|
||||||
- product_id: {{ ingredient.id }}
|
{{ ingredient_label(ingredient) }} {{ render_stock_fulfilment(ingredient, grocy.meta.fa_icons) }}
|
||||||
name: {{ ingredient.name}}
|
note: {{ ingredient.note }} {% endfor %}
|
||||||
description: {{ ingredient.description | default(null) }}
|
|
||||||
note: {{ ingredient.note }}
|
|
||||||
amount: {{ ingredient.amount }}
|
|
||||||
qu_id: {{ ingredient.qu_id }}
|
|
||||||
only_check_single_unit_in_stock: {{ ingredient.only_check_single_unit_in_stock }}
|
|
||||||
ingredient_group: {{ ingredient.ingredient_group | default(null) }}
|
|
||||||
not_check_stock_fulfillment: {{ ingredient.not_check_stock_fulfillment }}{% endfor %}
|
|
||||||
|
|
||||||
description: |-
|
description: |-
|
||||||
{{ grocy.fields.description }}
|
{{ grocy.fields.description }}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user