2019-03-03 19:29:38 -06:00
|
|
|
import click
|
2019-04-28 16:12:05 -05:00
|
|
|
from markdown import markdown
|
2019-04-01 00:16:32 -05:00
|
|
|
from jinja2 import Environment, FileSystemLoader
|
2019-06-16 23:54:10 -05:00
|
|
|
from grocy.conf import Configuration
|
|
|
|
from grocy.recipe import Recipe
|
|
|
|
from grocy.table import Table
|
|
|
|
from grocy.entity import Entity
|
|
|
|
from grocy.stock import Stock
|
2019-03-03 19:29:38 -06:00
|
|
|
import yaml
|
|
|
|
from sys import exit
|
2019-06-16 23:54:10 -05:00
|
|
|
from os import path
|
2019-03-03 19:29:38 -06:00
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
|
|
APP_NAME = 'grocy-cli'
|
|
|
|
SAMPLE_CONFIG_FILE = 'sample.config.yml'
|
2019-04-01 00:16:32 -05:00
|
|
|
TMP_DIR = '/tmp/grocy'
|
2019-03-03 19:29:38 -06:00
|
|
|
CONFIG_FILE = 'config.yml'
|
|
|
|
CONFIG_DIR = click.get_app_dir(APP_NAME)
|
|
|
|
PROJ_DIR = path.join(path.dirname(path.realpath(__file__)))
|
2019-06-16 23:54:10 -05:00
|
|
|
TEMPLATE_LOADER = Environment(loader=FileSystemLoader('templates'), trim_blocks=True, lstrip_blocks=True)
|
|
|
|
|
2019-03-03 19:29:38 -06:00
|
|
|
|
|
|
|
@click.group()
|
2019-06-16 23:54:10 -05:00
|
|
|
def main():
|
|
|
|
cfg = Configuration()
|
|
|
|
if not cfg.exists:
|
|
|
|
no_config_msg = 'A config file was not found. A sample configuration file'
|
|
|
|
no_config_msg += ' will be created under {}. Is that Ok?'.format(cfg.CONFIG_DIR)
|
2019-03-03 19:29:38 -06:00
|
|
|
create_config_app_dir = click.confirm(no_config_msg)
|
2019-06-16 23:54:10 -05:00
|
|
|
user_cfg_options = {}
|
2019-03-03 19:29:38 -06:00
|
|
|
if create_config_app_dir:
|
2019-06-16 23:54:10 -05:00
|
|
|
user_cfg_options['logger_level'] = click.prompt('Enter logger level',
|
|
|
|
default='DEBUG')
|
|
|
|
user_cfg_options['logger_file_location'] = click.prompt('Enter location for logger',
|
|
|
|
default=path.expanduser('~/.config/grocy/log'))
|
|
|
|
user_cfg_options['api'] = click.prompt('Enter the grocy api url',
|
|
|
|
default='https://demo-en.grocy.info/api')
|
|
|
|
user_cfg_options['token'] = click.prompt('Enter the grocy token ',
|
|
|
|
default='')
|
|
|
|
user_cfg_options['col_format'] = click.prompt('Enter the col position for rendering tables',
|
|
|
|
default='col')
|
|
|
|
user_cfg_options['table_format'] = click.prompt('Enter the table format',
|
|
|
|
default='simple')
|
|
|
|
cfg.create(user_cfg_options)
|
|
|
|
else:
|
2019-03-03 19:29:38 -06:00
|
|
|
exit(0)
|
2019-06-16 23:54:10 -05:00
|
|
|
else:
|
|
|
|
cfg.load()
|
2019-03-09 19:02:42 -06:00
|
|
|
|
2019-06-16 23:54:10 -05:00
|
|
|
logging.basicConfig(level=cfg.logger_level, filename=cfg.logger_file_location)
|
2019-03-03 19:29:38 -06:00
|
|
|
|
|
|
|
|
|
|
|
@main.command()
|
2019-06-16 23:54:10 -05:00
|
|
|
@click.pass_context
|
2019-03-09 19:02:42 -06:00
|
|
|
def stock(ctx):
|
2019-06-16 23:54:10 -05:00
|
|
|
logger = logging.getLogger('cli.stock')
|
|
|
|
if ctx.invoked_subcommand is None:
|
|
|
|
try:
|
2019-06-22 02:21:23 -05:00
|
|
|
stock = Stock()
|
|
|
|
table = Table(stocks=stock.products)
|
2019-06-16 23:54:10 -05:00
|
|
|
click.echo(table.stock)
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
raise e
|
2019-03-03 19:29:38 -06:00
|
|
|
|
2019-03-09 19:02:42 -06:00
|
|
|
|
2019-06-22 02:21:23 -05:00
|
|
|
@main.group(invoke_without_command=True)
|
|
|
|
@click.pass_context
|
|
|
|
@click.argument('product_id', required=False)
|
|
|
|
def product(ctx, product_id):
|
|
|
|
logger = logging.getLogger('cli.product')
|
|
|
|
try:
|
|
|
|
if product_id:
|
|
|
|
stock = Stock()
|
|
|
|
product = stock.get_product(product_id)
|
|
|
|
# Need to get quantity_unit
|
|
|
|
table = Table(entry=product)
|
|
|
|
click.echo(table.product)
|
|
|
|
else:
|
|
|
|
click.echo(ctx.get_help())
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
raise e
|
|
|
|
|
|
|
|
#@product.command('list')
|
|
|
|
#@click.argument('query', required=False)
|
|
|
|
#def view(query, product_id):
|
|
|
|
# logger = logging.getLogger('cli.product.view')
|
|
|
|
|
|
|
|
# try:
|
|
|
|
# if product_id:
|
|
|
|
# entity = Entity(name='product')
|
|
|
|
# product = entity.get(id=product_id)
|
|
|
|
# table = Table(product=product)
|
|
|
|
# click.echo(table.product)
|
|
|
|
# else:
|
|
|
|
# except Exception as e:
|
|
|
|
# logger.error(e)
|
|
|
|
# raise e
|
|
|
|
|
|
|
|
|
2019-03-09 19:02:42 -06:00
|
|
|
@main.command()
|
2019-06-16 23:54:10 -05:00
|
|
|
def shopping():
|
|
|
|
logger = logging.getLogger('cli.shopping')
|
|
|
|
try:
|
|
|
|
entity = Entity(name='shopping_list')
|
|
|
|
shopping_list = entity.get()
|
|
|
|
table = Table(shopping_list=shopping_list)
|
|
|
|
click.echo(table.shopping_list)
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
raise e
|
|
|
|
|
|
|
|
|
|
|
|
@main.group()
|
2019-06-22 02:21:23 -05:00
|
|
|
def ingredient():
|
2019-06-16 23:54:10 -05:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
@ingredient.command('add')
|
2019-06-22 02:21:23 -05:00
|
|
|
@click.argument('query')
|
|
|
|
@click.argument('recipe_id')
|
|
|
|
@click.option('--amount', '-a', 'amount', default=1, type=int)
|
|
|
|
@click.option('--group', '-g', type=str, default='')
|
|
|
|
@click.option('--variable-amount', '--va', 'variable_amount', default=None, type=float)
|
|
|
|
@click.option('--in-stock', '--is', 'in_stock', default=False)
|
|
|
|
@click.option('--disable-fulfillment', '--df', 'disable_fulfillment', default=False)
|
|
|
|
@click.option('--note', '-n', 'note', multiple=True, default='', type=str)
|
|
|
|
@click.option('--no-edit', '--ne', 'no_edit', default=False)
|
|
|
|
def add(query, recipe_id, amount, group, variable_amount, in_stock, disable_fulfillment, note, no_edit):
|
2019-06-16 23:54:10 -05:00
|
|
|
logger = logging.getLogger('cli.ingredient.add')
|
|
|
|
|
|
|
|
try:
|
|
|
|
loaded_template = TEMPLATE_LOADER.get_template('ingredient_add.yml')
|
2019-06-22 02:21:23 -05:00
|
|
|
new_ingredient = {}
|
|
|
|
|
|
|
|
entity = Entity(name='recipes')
|
|
|
|
recipe = entity.get(id=recipe_id)
|
|
|
|
|
|
|
|
if not recipe:
|
|
|
|
raise click.BadParameter(message='recipe {id} does not exist', param='recipe_id',
|
|
|
|
param_hint='Use `grocy recipes ls` to get a list of recipes')
|
|
|
|
|
|
|
|
entity = Entity(name='products')
|
|
|
|
product = entity.findOne(query)
|
|
|
|
new_ingredient['product_id'] = product['id']
|
|
|
|
|
|
|
|
new_ingredient['amount'] = amount
|
|
|
|
new_ingredient['group'] = group
|
|
|
|
new_ingredient['variable_amount'] = variable_amount
|
|
|
|
new_ingredient['only_check_single_unit_in_stock'] = "1" if in_stock else "0"
|
|
|
|
new_ingredient['not_check_stock_fulfillment'] = "1" if disable_fulfillment else "0"
|
|
|
|
new_ingredient['note'] = note
|
|
|
|
|
|
|
|
if not no_edit:
|
|
|
|
new_ingredient = click.edit(loaded_template.render(new_ingredient))
|
|
|
|
|
|
|
|
parsed_new_ingredient = yaml.safe_load(new_ingredient)
|
|
|
|
entity = Entity(name='recipes_pos')
|
|
|
|
#entity.create(parsed_new_ingredient)
|
2019-06-16 23:54:10 -05:00
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
2019-06-22 02:21:23 -05:00
|
|
|
raise e
|
2019-03-09 19:02:42 -06:00
|
|
|
|
|
|
|
|
2019-04-01 00:16:32 -05:00
|
|
|
@main.group()
|
2019-03-09 19:02:42 -06:00
|
|
|
@click.pass_context
|
|
|
|
def recipe(ctx):
|
2019-06-16 23:54:10 -05:00
|
|
|
pass
|
2019-03-09 19:02:42 -06:00
|
|
|
|
2019-06-16 23:54:10 -05:00
|
|
|
|
|
|
|
@recipe.command('ls')
|
|
|
|
def ls():
|
|
|
|
logger = logging.getLogger('cli.recipe')
|
|
|
|
try:
|
|
|
|
entity = Entity(name='recipes')
|
|
|
|
recipes = entity.get()
|
|
|
|
recipe = Recipe()
|
|
|
|
recipes_reqs = recipe.get_requirements()
|
|
|
|
table = Table(recipes=recipes, recipes_reqs=recipes_reqs)
|
|
|
|
click.echo(table.recipe)
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
raise e
|
2019-03-09 19:50:42 -06:00
|
|
|
|
2019-06-22 02:21:23 -05:00
|
|
|
|
2019-04-01 00:16:32 -05:00
|
|
|
@recipe.command('edit')
|
|
|
|
@click.argument('recipe_id')
|
2019-06-16 23:54:10 -05:00
|
|
|
def edit(recipe_id):
|
|
|
|
logger = logging.getLogger('cli.recipe.edit')
|
2019-04-01 00:16:32 -05:00
|
|
|
try:
|
|
|
|
if recipe_id:
|
2019-06-16 23:54:10 -05:00
|
|
|
entity = Entity(name='recipes')
|
|
|
|
recipe = entity.get(id=recipe_id)
|
2019-05-05 16:06:33 -05:00
|
|
|
loaded_template = TEMPLATE_LOADER.get_template('recipe_edit.yml')
|
2019-06-16 23:54:10 -05:00
|
|
|
edited_recipe = click.edit(loaded_template.render(recipe))
|
2019-04-01 00:16:32 -05:00
|
|
|
if edited_recipe is not None:
|
2019-04-28 16:12:05 -05:00
|
|
|
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()
|
2019-04-01 00:16:32 -05:00
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
2019-04-13 01:28:43 -05:00
|
|
|
logger.error('Could not edit recipe {}'.format(recipe_id))
|
2019-06-16 23:54:10 -05:00
|
|
|
raise e
|
2019-04-13 01:28:43 -05:00
|
|
|
|
|
|
|
|
2019-05-05 16:06:33 -05:00
|
|
|
@recipe.command('create')
|
|
|
|
@click.pass_context
|
|
|
|
def create(ctx):
|
2019-06-16 23:54:10 -05:00
|
|
|
logger = logging.getLogger('cli.recipe.create')
|
2019-05-05 16:06:33 -05:00
|
|
|
|
|
|
|
try:
|
2019-06-16 23:54:10 -05:00
|
|
|
recipe = Entity(name='recipes')
|
2019-05-05 16:06:33 -05:00
|
|
|
loaded_template = TEMPLATE_LOADER.get_template('recipe_add.yml')
|
|
|
|
new_recipe = click.edit(loaded_template.render())
|
|
|
|
if new_recipe is not None:
|
|
|
|
parsed_new_recipe = yaml.safe_load(new_recipe)
|
|
|
|
parsed_new_recipe['description'] = markdown(parsed_new_recipe['description'])
|
|
|
|
recipe.__dict__.update(parsed_new_recipe)
|
|
|
|
recipe.create()
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
2019-06-16 23:54:10 -05:00
|
|
|
raise e
|
|
|
|
|
2019-05-05 16:06:33 -05:00
|
|
|
|
2019-04-13 01:28:43 -05:00
|
|
|
#@main.command()
|
|
|
|
#@click.pass_context
|
|
|
|
#def chore(ctx):
|
|
|
|
# cfg = ctx.obj['cfg']
|
|
|
|
#
|
|
|
|
# chore = Chore(**cfg)
|
|
|
|
# chores = chore.get_list()
|
|
|
|
# click.echo(chores)
|
|
|
|
#
|
|
|
|
#@main.command()
|
|
|
|
#@click.pass_context
|
|
|
|
#def task(ctx):
|
|
|
|
# cfg = ctx.obj['cfg']
|
|
|
|
#
|
|
|
|
# task = Task(**cfg)
|
|
|
|
# tasks = task.get_list()
|
|
|
|
# click.echo(tasks)
|