2017-03-23 19:11:41 +01:00
|
|
|
#!/usr/bin/env python3
|
2017-03-21 11:26:25 +01:00
|
|
|
import click
|
|
|
|
from tabulate import tabulate
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
from pos.config import Config
|
|
|
|
from pos.logging import init_logging, get_logger
|
2017-03-24 21:04:10 +01:00
|
|
|
from pos.database import Database, User, Event, ProductCategory, Product,\
|
|
|
|
Transaction
|
2017-03-21 11:26:25 +01:00
|
|
|
|
|
|
|
config = Config()
|
|
|
|
conf_db = config.core['DATABASE']
|
|
|
|
|
|
|
|
init_logging(config.logging)
|
|
|
|
log = get_logger('cli')
|
|
|
|
|
|
|
|
db = Database(**conf_db)
|
|
|
|
|
|
|
|
|
2017-03-23 19:11:41 +01:00
|
|
|
def get_total(transaction):
|
|
|
|
return sum(o.product.price * o.quantity
|
|
|
|
for o in transaction.orders)
|
|
|
|
|
|
|
|
|
|
|
|
def get_income(event):
|
2017-03-24 21:08:32 +01:00
|
|
|
if event.transactions:
|
|
|
|
return sum(get_total(t) for t in event.transactions)
|
|
|
|
else:
|
|
|
|
return 0
|
2017-03-23 19:11:41 +01:00
|
|
|
|
|
|
|
|
2017-03-21 11:26:25 +01:00
|
|
|
@click.group()
|
|
|
|
def cli():
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2017-03-24 21:04:10 +01:00
|
|
|
@cli.command('initdb')
|
|
|
|
def initdb():
|
|
|
|
with db.get_session() as session:
|
|
|
|
categories = session.query(ProductCategory).count()
|
|
|
|
if not categories:
|
|
|
|
session.add(ProductCategory(name='Default'))
|
|
|
|
|
|
|
|
|
2017-03-21 11:26:25 +01:00
|
|
|
@cli.group('user')
|
|
|
|
def user():
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def tabulate_users(users):
|
|
|
|
tab = [["UID", "Username", "Enabled", "Created at"]]
|
|
|
|
for u in users:
|
|
|
|
tab.append([u.uid, u.username, u.is_active, u.created_at])
|
|
|
|
return tabulate(tab, headers='firstrow')
|
|
|
|
|
|
|
|
|
|
|
|
@user.command('add')
|
|
|
|
@click.argument('username')
|
|
|
|
@click.argument('password')
|
|
|
|
def user_add(username, password):
|
|
|
|
user = User(username=username, password=password)
|
|
|
|
with db.get_session() as session:
|
|
|
|
session.add(user)
|
2017-03-24 18:56:06 +01:00
|
|
|
print("User successfully added.")
|
2017-03-21 11:26:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
@user.command('list')
|
|
|
|
def user_list():
|
|
|
|
with db.get_session() as session:
|
|
|
|
users = session.query(User).all()
|
2017-03-23 19:11:41 +01:00
|
|
|
|
|
|
|
if users:
|
|
|
|
print(tabulate_users(users))
|
|
|
|
else:
|
2017-03-21 11:26:25 +01:00
|
|
|
print("No users found.")
|
|
|
|
|
|
|
|
|
2017-03-24 15:54:08 +01:00
|
|
|
@user.command('set')
|
|
|
|
@click.option('-p', '--password')
|
|
|
|
@click.argument('user_uid', type=click.INT)
|
|
|
|
def user_set(user_uid, password):
|
|
|
|
with db.get_session() as session:
|
|
|
|
user = session.query(User).get(user_uid)
|
|
|
|
|
|
|
|
if not user:
|
|
|
|
print("No user found with id #{}.".format(user_uid))
|
|
|
|
return
|
|
|
|
|
|
|
|
if password:
|
|
|
|
user.password = password
|
|
|
|
|
|
|
|
with db.get_session() as session:
|
|
|
|
session.add(user)
|
|
|
|
|
|
|
|
print("User successfully edited.")
|
|
|
|
|
|
|
|
|
2017-03-21 11:26:25 +01:00
|
|
|
@cli.group('event')
|
|
|
|
def event():
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def tabulate_events(events):
|
|
|
|
tab = [["UID", "Name", "Starts at", "Ends at", "Income", "Created at"]]
|
2017-03-23 19:11:41 +01:00
|
|
|
|
2017-03-21 11:26:25 +01:00
|
|
|
for e in events:
|
2017-03-23 19:11:41 +01:00
|
|
|
tab.append([e.uid, e.name, e.starts_at,
|
|
|
|
e.ends_at, get_income(e), e.created_at])
|
|
|
|
|
2017-03-21 11:26:25 +01:00
|
|
|
return tabulate(tab, headers='firstrow')
|
|
|
|
|
|
|
|
|
2017-03-24 15:08:28 +01:00
|
|
|
def get_overlapping_events(session, starts_at, ends_at):
|
2017-03-24 19:39:05 +01:00
|
|
|
events = session.query(Event)
|
2017-03-24 15:08:28 +01:00
|
|
|
|
|
|
|
if ends_at is None:
|
2017-03-24 19:39:05 +01:00
|
|
|
events = events.filter(Event.starts_at <= starts_at)
|
2017-03-24 15:08:28 +01:00
|
|
|
else:
|
2017-03-24 19:39:05 +01:00
|
|
|
events = events.filter(Event.ends_at >= starts_at)\
|
|
|
|
.filter(Event.starts_at <= ends_at)
|
2017-03-24 15:08:28 +01:00
|
|
|
|
2017-03-24 19:39:05 +01:00
|
|
|
return events.all()
|
2017-03-24 15:08:28 +01:00
|
|
|
|
|
|
|
|
2017-03-21 11:26:25 +01:00
|
|
|
@event.command('add')
|
|
|
|
@click.argument('name')
|
2017-03-24 15:08:28 +01:00
|
|
|
@click.argument('starts_at')
|
|
|
|
@click.argument('ends_at', required=False)
|
|
|
|
def event_add(name, starts_at, ends_at):
|
|
|
|
starts_at = datetime.strptime(starts_at, "%Y-%m-%d %H:%M")
|
|
|
|
ends_at = (datetime.strptime(ends_at, "%Y-%m-%d %H:%M")
|
|
|
|
if ends_at else None)
|
|
|
|
|
|
|
|
if ends_at and starts_at >= ends_at:
|
|
|
|
print("Could now add event: specified start date ({}) "
|
|
|
|
"is past the end date ({})."
|
|
|
|
.format(starts_at.strftime("%Y-%m-%d %H:%M"),
|
|
|
|
ends_at.strftime("%Y-%m-%d %H:%M")))
|
|
|
|
return
|
|
|
|
|
|
|
|
with db.get_session() as session:
|
|
|
|
events = get_overlapping_events(session, starts_at, ends_at)
|
|
|
|
if events:
|
|
|
|
print("Could not add event: another event is overlapping the date "
|
|
|
|
"range you have specified.")
|
|
|
|
print(tabulate_events(events))
|
|
|
|
return
|
2017-03-23 19:11:41 +01:00
|
|
|
|
2017-03-21 11:26:25 +01:00
|
|
|
with db.get_session() as session:
|
2017-03-24 15:08:28 +01:00
|
|
|
event = Event(name=name, starts_at=starts_at, ends_at=ends_at)
|
2017-03-21 11:26:25 +01:00
|
|
|
session.add(event)
|
2017-03-24 15:08:28 +01:00
|
|
|
session.flush()
|
2017-03-24 18:56:06 +01:00
|
|
|
print("Event successfully added.")
|
2017-03-24 15:08:28 +01:00
|
|
|
print(tabulate_events([event]))
|
2017-03-21 11:26:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
@event.command('list')
|
|
|
|
def event_list():
|
|
|
|
with db.get_session() as session:
|
|
|
|
events = session.query(Event).all()
|
2017-03-23 19:11:41 +01:00
|
|
|
|
|
|
|
if events:
|
|
|
|
print(tabulate_events(events))
|
|
|
|
else:
|
2017-03-21 11:26:25 +01:00
|
|
|
print("No events found.")
|
|
|
|
|
|
|
|
|
2017-03-24 15:08:28 +01:00
|
|
|
@event.command('set')
|
|
|
|
@click.option('-n', '--name')
|
|
|
|
@click.option('-s', '--start')
|
|
|
|
@click.option('-e', '--end')
|
|
|
|
@click.argument('event_uid')
|
|
|
|
def event_set(event_uid, name, start, end):
|
|
|
|
with db.get_session() as session:
|
|
|
|
event = session.query(Event).get(event_uid)
|
|
|
|
|
|
|
|
if not event:
|
|
|
|
print("No event found with id #{}.".format(event_uid))
|
|
|
|
return
|
|
|
|
|
|
|
|
if name:
|
|
|
|
event.name = name
|
|
|
|
|
|
|
|
if start:
|
|
|
|
starts_at = datetime.strptime(start, "%Y-%m-%d %H:%M")
|
|
|
|
|
|
|
|
if starts_at >= event.ends_at:
|
|
|
|
print("Could not edit event #{}: specified start date ({}) "
|
|
|
|
"is past the end date ({})"
|
|
|
|
.format(event.uid,
|
|
|
|
starts_at.strftime("%Y-%m-%d %H:%M"),
|
|
|
|
event.ends_at.strftime("%Y-%m-%d %H:%M")))
|
|
|
|
return
|
|
|
|
|
|
|
|
event.starts_at = starts_at
|
|
|
|
|
|
|
|
if end:
|
|
|
|
if end == 'none':
|
|
|
|
event.ends_at = None
|
|
|
|
elif end == 'now':
|
|
|
|
event.ends_at = datetime.now()
|
|
|
|
else:
|
|
|
|
ends_at = datetime.strptime(end, "%Y-%m-%d %H:%M")
|
|
|
|
|
|
|
|
if ends_at <= event.starts_at:
|
|
|
|
print("Could not edit event #{}: specified end date ({}) "
|
|
|
|
"is before the start date ({})"
|
|
|
|
.format(event.uid,
|
|
|
|
ends_at.strftime("%Y-%m-%d %H:%M"),
|
|
|
|
event.starts_at.strftime("%Y-%m-%d %H:%M")))
|
|
|
|
return
|
|
|
|
|
|
|
|
event.ends_at = datetime.strptime(end, "%Y-%m-%d %H:%M")
|
|
|
|
|
|
|
|
if event.starts_at and event.ends_at:
|
|
|
|
with db.get_session() as session:
|
|
|
|
events = get_overlapping_events(session,
|
|
|
|
event.starts_at, event.ends_at)
|
|
|
|
if events:
|
|
|
|
print("Could not edit event: another event is overlapping the "
|
|
|
|
"date range you have specified.")
|
|
|
|
print(tabulate_events(events))
|
|
|
|
return
|
|
|
|
|
|
|
|
if any([name, start, end]):
|
|
|
|
with db.get_session() as session:
|
|
|
|
session.add(event)
|
|
|
|
session.flush()
|
2017-03-24 18:56:06 +01:00
|
|
|
print("Event successfully edited.")
|
2017-03-24 15:08:28 +01:00
|
|
|
print(tabulate_events([event]))
|
|
|
|
|
|
|
|
|
2017-03-24 21:04:10 +01:00
|
|
|
@cli.group('category')
|
|
|
|
def category():
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
@category.command('add')
|
|
|
|
@click.option('-s', '--sort', type=click.INT)
|
|
|
|
@click.argument('name')
|
|
|
|
def category_add(name, sort):
|
|
|
|
category = ProductCategory(name=name)
|
|
|
|
|
|
|
|
if sort:
|
|
|
|
category.sort = sort
|
|
|
|
|
|
|
|
with db.get_session() as session:
|
|
|
|
session.add(category)
|
|
|
|
print("Category successfully added.")
|
|
|
|
|
|
|
|
|
|
|
|
def tabulate_categories(categories):
|
|
|
|
tab = [["UID", "Name", "Sort", "Created at"]]
|
|
|
|
for c in categories:
|
|
|
|
tab.append([c.uid, c.name, c.sort, c.created_at])
|
|
|
|
return tabulate(tab, headers='firstrow')
|
|
|
|
|
|
|
|
|
|
|
|
@category.command('list')
|
|
|
|
@click.option('-s', '--sort', is_flag=True)
|
|
|
|
def category_list(sort):
|
|
|
|
with db.get_session() as session:
|
|
|
|
categories = session.query(ProductCategory)
|
|
|
|
|
|
|
|
if sort:
|
|
|
|
categories = categories.order_by(ProductCategory.sort.asc())
|
|
|
|
|
|
|
|
categories = categories.all()
|
|
|
|
|
|
|
|
if categories:
|
|
|
|
print(tabulate_categories(categories))
|
|
|
|
else:
|
|
|
|
print("No categories found.")
|
|
|
|
|
|
|
|
|
2017-03-21 11:26:25 +01:00
|
|
|
@cli.group('product')
|
|
|
|
def product():
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def tabulate_products(products):
|
2017-03-24 21:04:10 +01:00
|
|
|
tab = [["UID", "Name", "Price", "Sort", "Category",
|
|
|
|
"Enabled", "Created at"]]
|
2017-03-21 11:26:25 +01:00
|
|
|
for p in products:
|
2017-03-24 21:04:10 +01:00
|
|
|
tab.append([p.uid, p.name, p.price, p.sort, p.category.name,
|
|
|
|
p.is_active, p.created_at])
|
2017-03-21 11:26:25 +01:00
|
|
|
return tabulate(tab, headers='firstrow')
|
|
|
|
|
|
|
|
|
|
|
|
@product.command('add')
|
|
|
|
@click.argument('name')
|
2017-03-26 21:09:46 +02:00
|
|
|
@click.argument('price', type=float)
|
2017-03-24 19:23:37 +01:00
|
|
|
@click.option('-s', '--sort', type=click.INT)
|
2017-03-24 21:04:10 +01:00
|
|
|
@click.option('-c', '--category', type=click.INT)
|
|
|
|
def product_add(name, price, sort, category):
|
2017-03-26 21:09:46 +02:00
|
|
|
price = int(price * 100)
|
2017-03-22 17:56:54 +01:00
|
|
|
product = Product(name=name, price=price)
|
2017-03-24 19:23:37 +01:00
|
|
|
|
|
|
|
if sort:
|
|
|
|
product.sort = sort
|
|
|
|
|
2017-03-24 21:04:10 +01:00
|
|
|
if category:
|
|
|
|
product.category_uid = category
|
|
|
|
else:
|
|
|
|
product.category_uid = 1
|
|
|
|
|
2017-03-21 11:26:25 +01:00
|
|
|
with db.get_session() as session:
|
|
|
|
session.add(product)
|
2017-03-24 18:56:06 +01:00
|
|
|
print("Product successfully added.")
|
2017-03-21 11:26:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
@product.command('list')
|
2017-03-24 19:23:37 +01:00
|
|
|
@click.option('-s', '--sort', is_flag=True)
|
|
|
|
def product_list(sort):
|
2017-03-21 11:26:25 +01:00
|
|
|
with db.get_session() as session:
|
2017-03-24 19:23:37 +01:00
|
|
|
products = session.query(Product)
|
|
|
|
|
|
|
|
if sort:
|
|
|
|
products = products.order_by(Product.sort.asc())
|
|
|
|
|
|
|
|
products = products.all()
|
2017-03-23 19:11:41 +01:00
|
|
|
|
|
|
|
if products:
|
|
|
|
print(tabulate_products(products))
|
|
|
|
else:
|
2017-03-21 11:26:25 +01:00
|
|
|
print("No products found.")
|
|
|
|
|
|
|
|
|
2017-03-24 19:23:37 +01:00
|
|
|
@product.command('set')
|
|
|
|
@click.option('-n', '--name')
|
|
|
|
@click.option('-p', '--price', type=click.INT)
|
|
|
|
@click.option('-s', '--sort', type=click.INT)
|
2017-03-24 21:04:10 +01:00
|
|
|
@click.option('-c', '--category', type=click.INT)
|
2017-03-24 19:23:37 +01:00
|
|
|
@click.argument('product_uid')
|
2017-03-24 21:04:10 +01:00
|
|
|
def product_set(product_uid, name, price, sort, category):
|
2017-03-24 19:23:37 +01:00
|
|
|
with db.get_session() as session:
|
|
|
|
product = session.query(Product).get(product_uid)
|
|
|
|
|
|
|
|
if not product:
|
|
|
|
print("No product found with id #{}.".format(product_uid))
|
|
|
|
return
|
|
|
|
|
|
|
|
if name:
|
|
|
|
product.name = name
|
|
|
|
|
|
|
|
if price:
|
|
|
|
product.price = price
|
|
|
|
|
|
|
|
if sort:
|
|
|
|
product.sort = sort
|
|
|
|
|
2017-03-24 21:04:10 +01:00
|
|
|
if category:
|
|
|
|
product.category_uid = category
|
|
|
|
|
|
|
|
if any([name, price, sort, category]):
|
2017-03-24 19:23:37 +01:00
|
|
|
with db.get_session() as session:
|
|
|
|
session.add(product)
|
|
|
|
print("Event successfully edited.")
|
|
|
|
print(tabulate_products([product]))
|
|
|
|
|
|
|
|
|
2017-03-22 17:12:15 +01:00
|
|
|
@cli.group('transaction')
|
|
|
|
def transaction():
|
2017-03-21 11:26:25 +01:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def tabulate_orders(orders):
|
2017-03-22 17:12:15 +01:00
|
|
|
tab = [["Product", "Price", "Quantity", "Total"]]
|
2017-03-21 11:26:25 +01:00
|
|
|
for o in orders:
|
2017-03-23 19:11:41 +01:00
|
|
|
if o.quantity > 0:
|
2017-03-22 17:12:15 +01:00
|
|
|
tab.append([o.product.name, o.product.price, o.quantity,
|
|
|
|
o.product.price * o.quantity])
|
|
|
|
return tabulate(tab, headers='firstrow')
|
|
|
|
|
|
|
|
|
|
|
|
def print_transactions(transactions):
|
|
|
|
for t in transactions:
|
|
|
|
print("Listing transaction #{} ({}):".format(t.uid, t.created_at))
|
|
|
|
print(tabulate_orders(t.orders))
|
2017-03-23 19:11:41 +01:00
|
|
|
print("Total:", get_total(t))
|
2017-03-22 17:12:15 +01:00
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
|
|
@transaction.command('list')
|
|
|
|
def transaction_list():
|
2017-03-21 11:26:25 +01:00
|
|
|
with db.get_session() as session:
|
2017-03-22 17:12:15 +01:00
|
|
|
transactions = session.query(Transaction).all()
|
|
|
|
|
2017-03-23 19:11:41 +01:00
|
|
|
if transactions:
|
|
|
|
print_transactions(transactions)
|
|
|
|
else:
|
2017-03-22 17:12:15 +01:00
|
|
|
print("No transactions found.")
|
2017-03-21 11:26:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
cli()
|