feat: Added add/remove ingredients sub commands to recipes
- feat: Added list recipe commands - feat: Added sample add ingredient template for recipe
This commit is contained in:
parent
05089108a9
commit
029ba35945
69
grocy/cli.py
69
grocy/cli.py
@ -9,6 +9,7 @@ from grocy.recipe import Recipe
|
|||||||
from grocy.table import Table
|
from grocy.table import Table
|
||||||
from grocy.entity import Entity
|
from grocy.entity import Entity
|
||||||
from grocy.stock import Stock
|
from grocy.stock import Stock
|
||||||
|
from grocy.schema import get_schema
|
||||||
import yaml
|
import yaml
|
||||||
from sys import exit
|
from sys import exit
|
||||||
from os import path
|
from os import path
|
||||||
@ -131,7 +132,7 @@ def edit(product_id, name):
|
|||||||
|
|
||||||
for index, edited_product in enumerate(parsed_edited_products):
|
for index, edited_product in enumerate(parsed_edited_products):
|
||||||
edited_product['id'] = products[index]['id']
|
edited_product['id'] = products[index]['id']
|
||||||
Util.verify_integrity(edited_product, schema)
|
util.verify_integrity(edited_product, schema)
|
||||||
entity.update(edited_product, id=products[index]['id'])
|
entity.update(edited_product, id=products[index]['id'])
|
||||||
else:
|
else:
|
||||||
raise click.BadParameter('Missing PRODUCT_ID or QUERY')
|
raise click.BadParameter('Missing PRODUCT_ID or QUERY')
|
||||||
@ -332,6 +333,7 @@ def browse(fullscreen, recipe_id):
|
|||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: revist this command
|
||||||
@recipe.command()
|
@recipe.command()
|
||||||
@click.option('--name', '-n', 'name')
|
@click.option('--name', '-n', 'name')
|
||||||
@click.argument('recipe_id', required=False)
|
@click.argument('recipe_id', required=False)
|
||||||
@ -342,11 +344,10 @@ def edit(recipe_id, name, template):
|
|||||||
cfg = Configuration()
|
cfg = Configuration()
|
||||||
util = Util(cfg=cfg)
|
util = Util(cfg=cfg)
|
||||||
cfg.load()
|
cfg.load()
|
||||||
loaded_template = cfg.templates('recipe/edit')
|
|
||||||
if template:
|
if template:
|
||||||
loaded_template = cfg.templates(template)
|
loaded_template = cfg.templates(template)
|
||||||
else:
|
else:
|
||||||
loaded_template = cfg.templates('recipe/list')
|
loaded_template = cfg.templates('recipe/edit')
|
||||||
|
|
||||||
entity = Entity(name='recipes')
|
entity = Entity(name='recipes')
|
||||||
if recipe_id:
|
if recipe_id:
|
||||||
@ -368,6 +369,7 @@ def edit(recipe_id, name, template):
|
|||||||
click.echo('Could not find recipe')
|
click.echo('Could not find recipe')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Build hydrated recipe entity object for editing
|
||||||
data = {'recipes': []}
|
data = {'recipes': []}
|
||||||
for recipe_entity in recipe_entities:
|
for recipe_entity in recipe_entities:
|
||||||
entry = {'fields': recipe_entity, 'meta': []}
|
entry = {'fields': recipe_entity, 'meta': []}
|
||||||
@ -386,17 +388,74 @@ def edit(recipe_id, name, template):
|
|||||||
if edited_recipes is None:
|
if edited_recipes is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
schema = []
|
||||||
|
schema.append(Entity(name='products').schema)
|
||||||
|
schema.append(Entity(name='locations').schema)
|
||||||
|
schema.append(Entity(name='quantity_units').schema)
|
||||||
|
schema.append(Entity(name='recipes').schema)
|
||||||
|
|
||||||
parsed_edited_recipes = util.load_yaml(edited_recipes)
|
parsed_edited_recipes = util.load_yaml(edited_recipes)
|
||||||
for index, edited_recipe in enumerate(parsed_edited_recipes):
|
for index, edited_recipe in enumerate(parsed_edited_recipes):
|
||||||
|
schema = entity.schema
|
||||||
edited_recipe['id'] = recipe_entities[index]['id']
|
edited_recipe['id'] = recipe_entities[index]['id']
|
||||||
# Util.verify_integrity(edited_recipe, schema)
|
util.verify_integrity(edited_recipe, schema)
|
||||||
entity.update(edited_recipe, id=recipe[index]['id'])
|
entity.update(edited_recipe, id=edited_recipe['id'])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise click.BadParameter('Missing RECIPE_ID or QUERY')
|
raise click.BadParameter('Missing RECIPE_ID or QUERY')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
raise e
|
raise e
|
||||||
|
@recipe.command()
|
||||||
|
@click.argument('recipe_id', required=True)
|
||||||
|
@click.option('-t', 'template')
|
||||||
|
def add_ingredient(recipe_id, template):
|
||||||
|
logger = logging.getLogger('cli.recipe.add_ingredient')
|
||||||
|
try:
|
||||||
|
cfg = Configuration()
|
||||||
|
util = Util(cfg=cfg)
|
||||||
|
cfg.load()
|
||||||
|
if template:
|
||||||
|
loaded_template = cfg.templates(template)
|
||||||
|
else:
|
||||||
|
loaded_template = cfg.templates('recipe/add-ingredient')
|
||||||
|
|
||||||
|
# Verify that recipe exist
|
||||||
|
try:
|
||||||
|
entity = Entity(name='recipes')
|
||||||
|
entity.get(id=recipe_id)
|
||||||
|
except Exception:
|
||||||
|
raise Exception('Could not find recipe {}'.format(recipe_id))
|
||||||
|
|
||||||
|
# TODO: Meta has to be added to validate against know fields/properties
|
||||||
|
# Add quantity_units to meta
|
||||||
|
ingredient = click.edit(loaded_template.render(), extension='.yml')
|
||||||
|
if ingredient is None:
|
||||||
|
return
|
||||||
|
parsed_new_ingredient = util.load_yaml(ingredient)[0]
|
||||||
|
parsed_new_ingredient['recipe_id'] = recipe_id
|
||||||
|
|
||||||
|
if template == 'debug':
|
||||||
|
click.echo(parsed_new_ingredient)
|
||||||
|
return
|
||||||
|
entity = Entity(name='recipes_pos')
|
||||||
|
entity.create(parsed_new_ingredient)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
@recipe.command()
|
||||||
|
@click.argument('recipe_id', required=True)
|
||||||
|
@click.argument('ingredient_id', required=True)
|
||||||
|
def remove_ingredient(recipe_id, ingredient_id):
|
||||||
|
logger = logging.getLogger('cli.recipe.remove_ingredient')
|
||||||
|
try:
|
||||||
|
entity = Entity(name='recipes_pos')
|
||||||
|
entity.delete(ingredient_id)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
#@main.command()
|
#@main.command()
|
||||||
#def shopping():
|
#def shopping():
|
||||||
|
@ -14,7 +14,8 @@ class Entity(object):
|
|||||||
'stock': 'StockEntry',
|
'stock': 'StockEntry',
|
||||||
'product_groups':'ProductGroup',
|
'product_groups':'ProductGroup',
|
||||||
'locations': 'Location',
|
'locations': 'Location',
|
||||||
'quantity_units': 'QuantityUnit'
|
'quantity_units': 'QuantityUnit',
|
||||||
|
'recipes': 'Recipe'
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, name, **props):
|
def __init__(self, name, **props):
|
||||||
@ -65,8 +66,6 @@ class Entity(object):
|
|||||||
if type(value) == bool:
|
if type(value) == bool:
|
||||||
entity[key] = '1' if value else '0'
|
entity[key] = '1' if value else '0'
|
||||||
|
|
||||||
print('{}'.format(entity))
|
|
||||||
|
|
||||||
request = Request('post', url, resource=entity)
|
request = Request('post', url, resource=entity)
|
||||||
try:
|
try:
|
||||||
return request.send()
|
return request.send()
|
||||||
@ -87,6 +86,19 @@ class Entity(object):
|
|||||||
logger.error(e)
|
logger.error(e)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
def delete(self, id=None):
|
||||||
|
if id is None:
|
||||||
|
raise Exception('id property is required to delete entity')
|
||||||
|
logger = logging.getLogger('entity.delete')
|
||||||
|
url = self.RESOURCE_URL_TEMPLATE.format(domain=self.conf.domain, entity=self.name, objectId=id)
|
||||||
|
|
||||||
|
request = Request('delete', url)
|
||||||
|
try:
|
||||||
|
return request.send()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def schema(self):
|
def schema(self):
|
||||||
logger = logging.getLogger('entity.schema')
|
logger = logging.getLogger('entity.schema')
|
||||||
|
@ -11,7 +11,6 @@ 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/{recipeId}/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/{recipePosId}/fulfillment'
|
|
||||||
|
|
||||||
def __init__(self, id=None):
|
def __init__(self, id=None):
|
||||||
self.conf = Configuration()
|
self.conf = Configuration()
|
||||||
@ -104,3 +103,4 @@ class Recipe(object):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ SCHEMA_MODEL_MAP = {
|
|||||||
'product_groups': 'ProductGroup',
|
'product_groups': 'ProductGroup',
|
||||||
'locations': 'Location',
|
'locations': 'Location',
|
||||||
'quantity_units': 'QuantityUnit',
|
'quantity_units': 'QuantityUnit',
|
||||||
'recipe_fulfillment': 'RecipeFulfillmentResponse'
|
'recipe_fulfillment': 'RecipeFulfillmentResponse',
|
||||||
|
'recipe_pos_fulfillment': 'RecipePosFulfillmentResponse'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,15 +16,24 @@ class Util(object):
|
|||||||
data_list = list(generator)
|
data_list = list(generator)
|
||||||
return data_list
|
return data_list
|
||||||
|
|
||||||
|
def verify_integrity(self, new_data, schema):
|
||||||
def verify_integrity(new_data, schema):
|
|
||||||
logger = logging.getLogger('util.verify_integrity')
|
logger = logging.getLogger('util.verify_integrity')
|
||||||
try:
|
try:
|
||||||
# Verify that updated fields exist
|
# Verify that updated fields exist
|
||||||
schema_keys = schema['properties'].keys()
|
if type(schema) != list:
|
||||||
for prop in new_data.keys():
|
schemas = [schema]
|
||||||
if prop not in schema_keys:
|
else:
|
||||||
raise Exception('{} is not a valid field'.format(prop))
|
schemas = schema
|
||||||
|
|
||||||
|
keys_not_found = []
|
||||||
|
for current_schema in schemas:
|
||||||
|
schema_keys = current_schema['properties'].keys()
|
||||||
|
for prop in new_data.keys():
|
||||||
|
if prop not in schema_keys:
|
||||||
|
keys_not_found.append(prop)
|
||||||
|
print('{}'.format(keys_not_found))
|
||||||
|
if len(keys_not_found) > 0:
|
||||||
|
raise Exception('{} is not valid property'.format(keys_not_found.join(', ')))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
raise e
|
raise e
|
||||||
|
8
templates/recipe/add-ingredient.yml
Normal file
8
templates/recipe/add-ingredient.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
product_id:
|
||||||
|
amount:
|
||||||
|
qu_id:
|
||||||
|
only_check_single_unit_in_stock:
|
||||||
|
not_check_stock_fulfilment:
|
||||||
|
variable_amount:
|
||||||
|
ingredient_group:
|
||||||
|
note:
|
@ -1,7 +1,8 @@
|
|||||||
{% from 'recipe/macro.yml' import render_recipe_fulfilment %}
|
{% from 'recipe/macro.yml' import render_recipe_fulfilment %}
|
||||||
{% for recipe in grocy.recipes %}
|
{% for recipe in grocy.recipes %}
|
||||||
|
id: {{ recipe.fields.id }}
|
||||||
name: {{ recipe.fields.name }}
|
name: {{ recipe.fields.name }}
|
||||||
servings: {{ recipe.fields.base_servings }}
|
base_servings: {{ recipe.fields.base_servings }}
|
||||||
required_fulfilled: {{ render_recipe_fulfilment(recipe.fields.fulfillment, grocy.meta.fa_icons) }}
|
required_fulfilled: {{ render_recipe_fulfilment(recipe.fields.fulfillment, grocy.meta.fa_icons) }}
|
||||||
description: |-
|
description: |-
|
||||||
{{ recipe.fields.description }}
|
{{ recipe.fields.description }}
|
||||||
|
Loading…
Reference in New Issue
Block a user